diff options
author | James Morris <jmorris@namei.org> | 2009-06-10 21:03:14 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-06-10 21:03:14 -0400 |
commit | 73fbad283cfbbcf02939bdbda31fc4a30e729cca (patch) | |
tree | 7c89fe13e1b4a2c7f2d60f4ea6eaf69c14bccab7 | |
parent | 769f3e8c384795cc350e2aae27de2a12374d19d4 (diff) | |
parent | 35f2c2f6f6ae13ef23c4f68e6d3073753077ca43 (diff) |
Merge branch 'next' into for-linus
58 files changed, 1946 insertions, 477 deletions
diff --git a/Documentation/Smack.txt b/Documentation/Smack.txt index 629c92e99783..34614b4c708e 100644 --- a/Documentation/Smack.txt +++ b/Documentation/Smack.txt | |||
@@ -184,8 +184,9 @@ length. Single character labels using special characters, that being anything | |||
184 | other than a letter or digit, are reserved for use by the Smack development | 184 | other than a letter or digit, are reserved for use by the Smack development |
185 | team. Smack labels are unstructured, case sensitive, and the only operation | 185 | team. Smack labels are unstructured, case sensitive, and the only operation |
186 | ever performed on them is comparison for equality. Smack labels cannot | 186 | ever performed on them is comparison for equality. Smack labels cannot |
187 | contain unprintable characters or the "/" (slash) character. Smack labels | 187 | contain unprintable characters, the "/" (slash), the "\" (backslash), the "'" |
188 | cannot begin with a '-', which is reserved for special options. | 188 | (quote) and '"' (double-quote) characters. |
189 | Smack labels cannot begin with a '-', which is reserved for special options. | ||
189 | 190 | ||
190 | There are some predefined labels: | 191 | There are some predefined labels: |
191 | 192 | ||
@@ -523,3 +524,18 @@ Smack supports some mount options: | |||
523 | 524 | ||
524 | These mount options apply to all file system types. | 525 | These mount options apply to all file system types. |
525 | 526 | ||
527 | Smack auditing | ||
528 | |||
529 | If you want Smack auditing of security events, you need to set CONFIG_AUDIT | ||
530 | in your kernel configuration. | ||
531 | By default, all denied events will be audited. You can change this behavior by | ||
532 | writing a single character to the /smack/logging file : | ||
533 | 0 : no logging | ||
534 | 1 : log denied (default) | ||
535 | 2 : log accepted | ||
536 | 3 : log denied & accepted | ||
537 | |||
538 | Events are logged as 'key=value' pairs, for each event you at least will get | ||
539 | the subjet, the object, the rights requested, the action, the kernel function | ||
540 | that triggered the event, plus other pairs depending on the type of event | ||
541 | audited. | ||
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index af43f45e8358..a5253f6d01af 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -916,6 +916,12 @@ and is between 256 and 4096 characters. It is defined in the file | |||
916 | Formt: { "sha1" | "md5" } | 916 | Formt: { "sha1" | "md5" } |
917 | default: "sha1" | 917 | default: "sha1" |
918 | 918 | ||
919 | ima_tcb [IMA] | ||
920 | Load a policy which meets the needs of the Trusted | ||
921 | Computing Base. This means IMA will measure all | ||
922 | programs exec'd, files mmap'd for exec, and all files | ||
923 | opened for read by uid=0. | ||
924 | |||
919 | in2000= [HW,SCSI] | 925 | in2000= [HW,SCSI] |
920 | See header of drivers/scsi/in2000.c. | 926 | See header of drivers/scsi/in2000.c. |
921 | 927 | ||
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index f11ca7979fa6..322a00bb99d9 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt | |||
@@ -32,6 +32,7 @@ show up in /proc/sys/kernel: | |||
32 | - kstack_depth_to_print [ X86 only ] | 32 | - kstack_depth_to_print [ X86 only ] |
33 | - l2cr [ PPC only ] | 33 | - l2cr [ PPC only ] |
34 | - modprobe ==> Documentation/debugging-modules.txt | 34 | - modprobe ==> Documentation/debugging-modules.txt |
35 | - modules_disabled | ||
35 | - msgmax | 36 | - msgmax |
36 | - msgmnb | 37 | - msgmnb |
37 | - msgmni | 38 | - msgmni |
@@ -184,6 +185,16 @@ kernel stack. | |||
184 | 185 | ||
185 | ============================================================== | 186 | ============================================================== |
186 | 187 | ||
188 | modules_disabled: | ||
189 | |||
190 | A toggle value indicating if modules are allowed to be loaded | ||
191 | in an otherwise modular kernel. This toggle defaults to off | ||
192 | (0), but can be set true (1). Once true, modules can be | ||
193 | neither loaded nor unloaded, and the toggle cannot be set back | ||
194 | to false. | ||
195 | |||
196 | ============================================================== | ||
197 | |||
187 | osrelease, ostype & version: | 198 | osrelease, ostype & version: |
188 | 199 | ||
189 | # cat osrelease | 200 | # cat osrelease |
diff --git a/fs/compat.c b/fs/compat.c index 681ed81e6be0..bb2a9b2e8173 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -1488,7 +1488,7 @@ int compat_do_execve(char * filename, | |||
1488 | if (!bprm) | 1488 | if (!bprm) |
1489 | goto out_files; | 1489 | goto out_files; |
1490 | 1490 | ||
1491 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | 1491 | retval = mutex_lock_interruptible(¤t->cred_guard_mutex); |
1492 | if (retval < 0) | 1492 | if (retval < 0) |
1493 | goto out_free; | 1493 | goto out_free; |
1494 | current->in_execve = 1; | 1494 | current->in_execve = 1; |
@@ -1550,7 +1550,7 @@ int compat_do_execve(char * filename, | |||
1550 | /* execve succeeded */ | 1550 | /* execve succeeded */ |
1551 | current->fs->in_exec = 0; | 1551 | current->fs->in_exec = 0; |
1552 | current->in_execve = 0; | 1552 | current->in_execve = 0; |
1553 | mutex_unlock(¤t->cred_exec_mutex); | 1553 | mutex_unlock(¤t->cred_guard_mutex); |
1554 | acct_update_integrals(current); | 1554 | acct_update_integrals(current); |
1555 | free_bprm(bprm); | 1555 | free_bprm(bprm); |
1556 | if (displaced) | 1556 | if (displaced) |
@@ -1573,7 +1573,7 @@ out_unmark: | |||
1573 | 1573 | ||
1574 | out_unlock: | 1574 | out_unlock: |
1575 | current->in_execve = 0; | 1575 | current->in_execve = 0; |
1576 | mutex_unlock(¤t->cred_exec_mutex); | 1576 | mutex_unlock(¤t->cred_guard_mutex); |
1577 | 1577 | ||
1578 | out_free: | 1578 | out_free: |
1579 | free_bprm(bprm); | 1579 | free_bprm(bprm); |
@@ -1016,7 +1016,7 @@ void install_exec_creds(struct linux_binprm *bprm) | |||
1016 | commit_creds(bprm->cred); | 1016 | commit_creds(bprm->cred); |
1017 | bprm->cred = NULL; | 1017 | bprm->cred = NULL; |
1018 | 1018 | ||
1019 | /* cred_exec_mutex must be held at least to this point to prevent | 1019 | /* cred_guard_mutex must be held at least to this point to prevent |
1020 | * ptrace_attach() from altering our determination of the task's | 1020 | * ptrace_attach() from altering our determination of the task's |
1021 | * credentials; any time after this it may be unlocked */ | 1021 | * credentials; any time after this it may be unlocked */ |
1022 | 1022 | ||
@@ -1026,7 +1026,7 @@ EXPORT_SYMBOL(install_exec_creds); | |||
1026 | 1026 | ||
1027 | /* | 1027 | /* |
1028 | * determine how safe it is to execute the proposed program | 1028 | * determine how safe it is to execute the proposed program |
1029 | * - the caller must hold current->cred_exec_mutex to protect against | 1029 | * - the caller must hold current->cred_guard_mutex to protect against |
1030 | * PTRACE_ATTACH | 1030 | * PTRACE_ATTACH |
1031 | */ | 1031 | */ |
1032 | int check_unsafe_exec(struct linux_binprm *bprm) | 1032 | int check_unsafe_exec(struct linux_binprm *bprm) |
@@ -1268,7 +1268,7 @@ int do_execve(char * filename, | |||
1268 | if (!bprm) | 1268 | if (!bprm) |
1269 | goto out_files; | 1269 | goto out_files; |
1270 | 1270 | ||
1271 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | 1271 | retval = mutex_lock_interruptible(¤t->cred_guard_mutex); |
1272 | if (retval < 0) | 1272 | if (retval < 0) |
1273 | goto out_free; | 1273 | goto out_free; |
1274 | current->in_execve = 1; | 1274 | current->in_execve = 1; |
@@ -1331,7 +1331,7 @@ int do_execve(char * filename, | |||
1331 | /* execve succeeded */ | 1331 | /* execve succeeded */ |
1332 | current->fs->in_exec = 0; | 1332 | current->fs->in_exec = 0; |
1333 | current->in_execve = 0; | 1333 | current->in_execve = 0; |
1334 | mutex_unlock(¤t->cred_exec_mutex); | 1334 | mutex_unlock(¤t->cred_guard_mutex); |
1335 | acct_update_integrals(current); | 1335 | acct_update_integrals(current); |
1336 | free_bprm(bprm); | 1336 | free_bprm(bprm); |
1337 | if (displaced) | 1337 | if (displaced) |
@@ -1354,7 +1354,7 @@ out_unmark: | |||
1354 | 1354 | ||
1355 | out_unlock: | 1355 | out_unlock: |
1356 | current->in_execve = 0; | 1356 | current->in_execve = 0; |
1357 | mutex_unlock(¤t->cred_exec_mutex); | 1357 | mutex_unlock(¤t->cred_guard_mutex); |
1358 | 1358 | ||
1359 | out_free: | 1359 | out_free: |
1360 | free_bprm(bprm); | 1360 | free_bprm(bprm); |
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index c1462d43e721..941c8425c10b 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/dnotify.h> | 30 | #include <linux/dnotify.h> |
31 | #include <linux/statfs.h> | 31 | #include <linux/statfs.h> |
32 | #include <linux/security.h> | 32 | #include <linux/security.h> |
33 | #include <linux/ima.h> | ||
33 | 34 | ||
34 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
35 | 36 | ||
@@ -986,6 +987,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag) | |||
986 | &hugetlbfs_file_operations); | 987 | &hugetlbfs_file_operations); |
987 | if (!file) | 988 | if (!file) |
988 | goto out_dentry; /* inode is already attached */ | 989 | goto out_dentry; /* inode is already attached */ |
990 | ima_counts_get(file); | ||
989 | 991 | ||
990 | return file; | 992 | return file; |
991 | 993 | ||
diff --git a/fs/namei.c b/fs/namei.c index 967c3db92724..c82805d088e1 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -853,7 +853,8 @@ static int __link_path_walk(const char *name, struct nameidata *nd) | |||
853 | err = inode_permission(nd->path.dentry->d_inode, | 853 | err = inode_permission(nd->path.dentry->d_inode, |
854 | MAY_EXEC); | 854 | MAY_EXEC); |
855 | if (!err) | 855 | if (!err) |
856 | err = ima_path_check(&nd->path, MAY_EXEC); | 856 | err = ima_path_check(&nd->path, MAY_EXEC, |
857 | IMA_COUNT_UPDATE); | ||
857 | if (err) | 858 | if (err) |
858 | break; | 859 | break; |
859 | 860 | ||
@@ -1515,7 +1516,8 @@ int may_open(struct path *path, int acc_mode, int flag) | |||
1515 | return error; | 1516 | return error; |
1516 | 1517 | ||
1517 | error = ima_path_check(path, | 1518 | error = ima_path_check(path, |
1518 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC)); | 1519 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC), |
1520 | IMA_COUNT_UPDATE); | ||
1519 | if (error) | 1521 | if (error) |
1520 | return error; | 1522 | return error; |
1521 | /* | 1523 | /* |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index b660435978d2..bd584bcf1d9f 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -55,6 +55,7 @@ | |||
55 | #include <linux/security.h> | 55 | #include <linux/security.h> |
56 | #endif /* CONFIG_NFSD_V4 */ | 56 | #endif /* CONFIG_NFSD_V4 */ |
57 | #include <linux/jhash.h> | 57 | #include <linux/jhash.h> |
58 | #include <linux/ima.h> | ||
58 | 59 | ||
59 | #include <asm/uaccess.h> | 60 | #include <asm/uaccess.h> |
60 | 61 | ||
@@ -735,6 +736,8 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
735 | flags, cred); | 736 | flags, cred); |
736 | if (IS_ERR(*filp)) | 737 | if (IS_ERR(*filp)) |
737 | host_err = PTR_ERR(*filp); | 738 | host_err = PTR_ERR(*filp); |
739 | else | ||
740 | ima_counts_get(*filp); | ||
738 | out_nfserr: | 741 | out_nfserr: |
739 | err = nfserrno(host_err); | 742 | err = nfserrno(host_err); |
740 | out: | 743 | out: |
@@ -2024,6 +2027,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
2024 | struct dentry *dentry, int acc) | 2027 | struct dentry *dentry, int acc) |
2025 | { | 2028 | { |
2026 | struct inode *inode = dentry->d_inode; | 2029 | struct inode *inode = dentry->d_inode; |
2030 | struct path path; | ||
2027 | int err; | 2031 | int err; |
2028 | 2032 | ||
2029 | if (acc == NFSD_MAY_NOP) | 2033 | if (acc == NFSD_MAY_NOP) |
@@ -2096,7 +2100,17 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
2096 | if (err == -EACCES && S_ISREG(inode->i_mode) && | 2100 | if (err == -EACCES && S_ISREG(inode->i_mode) && |
2097 | acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) | 2101 | acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) |
2098 | err = inode_permission(inode, MAY_EXEC); | 2102 | err = inode_permission(inode, MAY_EXEC); |
2103 | if (err) | ||
2104 | goto nfsd_out; | ||
2099 | 2105 | ||
2106 | /* Do integrity (permission) checking now, but defer incrementing | ||
2107 | * IMA counts to the actual file open. | ||
2108 | */ | ||
2109 | path.mnt = exp->ex_path.mnt; | ||
2110 | path.dentry = dentry; | ||
2111 | err = ima_path_check(&path, acc & (MAY_READ | MAY_WRITE | MAY_EXEC), | ||
2112 | IMA_COUNT_LEAVE); | ||
2113 | nfsd_out: | ||
2100 | return err? nfserrno(err) : 0; | 2114 | return err? nfserrno(err) : 0; |
2101 | } | 2115 | } |
2102 | 2116 | ||
diff --git a/fs/proc/base.c b/fs/proc/base.c index 3326bbf9ab95..1539e630c47d 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -2128,9 +2128,15 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, | |||
2128 | if (copy_from_user(page, buf, count)) | 2128 | if (copy_from_user(page, buf, count)) |
2129 | goto out_free; | 2129 | goto out_free; |
2130 | 2130 | ||
2131 | /* Guard against adverse ptrace interaction */ | ||
2132 | length = mutex_lock_interruptible(&task->cred_guard_mutex); | ||
2133 | if (length < 0) | ||
2134 | goto out_free; | ||
2135 | |||
2131 | length = security_setprocattr(task, | 2136 | length = security_setprocattr(task, |
2132 | (char*)file->f_path.dentry->d_name.name, | 2137 | (char*)file->f_path.dentry->d_name.name, |
2133 | (void*)page, count); | 2138 | (void*)page, count); |
2139 | mutex_unlock(&task->cred_guard_mutex); | ||
2134 | out_free: | 2140 | out_free: |
2135 | free_page((unsigned long) page); | 2141 | free_page((unsigned long) page); |
2136 | out: | 2142 | out: |
diff --git a/include/linux/ima.h b/include/linux/ima.h index 0e2aa45cb0ce..b1b827d091a9 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h | |||
@@ -13,14 +13,17 @@ | |||
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | struct linux_binprm; | 14 | struct linux_binprm; |
15 | 15 | ||
16 | #define IMA_COUNT_UPDATE 1 | ||
17 | #define IMA_COUNT_LEAVE 0 | ||
18 | |||
16 | #ifdef CONFIG_IMA | 19 | #ifdef CONFIG_IMA |
17 | extern int ima_bprm_check(struct linux_binprm *bprm); | 20 | extern int ima_bprm_check(struct linux_binprm *bprm); |
18 | extern int ima_inode_alloc(struct inode *inode); | 21 | extern int ima_inode_alloc(struct inode *inode); |
19 | extern void ima_inode_free(struct inode *inode); | 22 | extern void ima_inode_free(struct inode *inode); |
20 | extern int ima_path_check(struct path *path, int mask); | 23 | extern int ima_path_check(struct path *path, int mask, int update_counts); |
21 | extern void ima_file_free(struct file *file); | 24 | extern void ima_file_free(struct file *file); |
22 | extern int ima_file_mmap(struct file *file, unsigned long prot); | 25 | extern int ima_file_mmap(struct file *file, unsigned long prot); |
23 | extern void ima_shm_check(struct file *file); | 26 | extern void ima_counts_get(struct file *file); |
24 | 27 | ||
25 | #else | 28 | #else |
26 | static inline int ima_bprm_check(struct linux_binprm *bprm) | 29 | static inline int ima_bprm_check(struct linux_binprm *bprm) |
@@ -38,7 +41,7 @@ static inline void ima_inode_free(struct inode *inode) | |||
38 | return; | 41 | return; |
39 | } | 42 | } |
40 | 43 | ||
41 | static inline int ima_path_check(struct path *path, int mask) | 44 | static inline int ima_path_check(struct path *path, int mask, int update_counts) |
42 | { | 45 | { |
43 | return 0; | 46 | return 0; |
44 | } | 47 | } |
@@ -53,7 +56,7 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot) | |||
53 | return 0; | 56 | return 0; |
54 | } | 57 | } |
55 | 58 | ||
56 | static inline void ima_shm_check(struct file *file) | 59 | static inline void ima_counts_get(struct file *file) |
57 | { | 60 | { |
58 | return; | 61 | return; |
59 | } | 62 | } |
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index d87247d2641f..7f54ba942429 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
@@ -145,8 +145,8 @@ extern struct cred init_cred; | |||
145 | .group_leader = &tsk, \ | 145 | .group_leader = &tsk, \ |
146 | .real_cred = &init_cred, \ | 146 | .real_cred = &init_cred, \ |
147 | .cred = &init_cred, \ | 147 | .cred = &init_cred, \ |
148 | .cred_exec_mutex = \ | 148 | .cred_guard_mutex = \ |
149 | __MUTEX_INITIALIZER(tsk.cred_exec_mutex), \ | 149 | __MUTEX_INITIALIZER(tsk.cred_guard_mutex), \ |
150 | .comm = "swapper", \ | 150 | .comm = "swapper", \ |
151 | .thread = INIT_THREAD, \ | 151 | .thread = INIT_THREAD, \ |
152 | .fs = &init_fs, \ | 152 | .fs = &init_fs, \ |
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h new file mode 100644 index 000000000000..e461b2c3d711 --- /dev/null +++ b/include/linux/lsm_audit.h | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * Common LSM logging functions | ||
3 | * Heavily borrowed from selinux/avc.h | ||
4 | * | ||
5 | * Author : Etienne BASSET <etienne.basset@ensta.org> | ||
6 | * | ||
7 | * All credits to : Stephen Smalley, <sds@epoch.ncsc.mil> | ||
8 | * All BUGS to : Etienne BASSET <etienne.basset@ensta.org> | ||
9 | */ | ||
10 | #ifndef _LSM_COMMON_LOGGING_ | ||
11 | #define _LSM_COMMON_LOGGING_ | ||
12 | |||
13 | #include <linux/stddef.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/kdev_t.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/audit.h> | ||
20 | #include <linux/in6.h> | ||
21 | #include <linux/path.h> | ||
22 | #include <linux/key.h> | ||
23 | #include <linux/skbuff.h> | ||
24 | #include <asm/system.h> | ||
25 | |||
26 | |||
27 | /* Auxiliary data to use in generating the audit record. */ | ||
28 | struct common_audit_data { | ||
29 | char type; | ||
30 | #define LSM_AUDIT_DATA_FS 1 | ||
31 | #define LSM_AUDIT_DATA_NET 2 | ||
32 | #define LSM_AUDIT_DATA_CAP 3 | ||
33 | #define LSM_AUDIT_DATA_IPC 4 | ||
34 | #define LSM_AUDIT_DATA_TASK 5 | ||
35 | #define LSM_AUDIT_DATA_KEY 6 | ||
36 | struct task_struct *tsk; | ||
37 | union { | ||
38 | struct { | ||
39 | struct path path; | ||
40 | struct inode *inode; | ||
41 | } fs; | ||
42 | struct { | ||
43 | int netif; | ||
44 | struct sock *sk; | ||
45 | u16 family; | ||
46 | __be16 dport; | ||
47 | __be16 sport; | ||
48 | union { | ||
49 | struct { | ||
50 | __be32 daddr; | ||
51 | __be32 saddr; | ||
52 | } v4; | ||
53 | struct { | ||
54 | struct in6_addr daddr; | ||
55 | struct in6_addr saddr; | ||
56 | } v6; | ||
57 | } fam; | ||
58 | } net; | ||
59 | int cap; | ||
60 | int ipc_id; | ||
61 | struct task_struct *tsk; | ||
62 | #ifdef CONFIG_KEYS | ||
63 | struct { | ||
64 | key_serial_t key; | ||
65 | char *key_desc; | ||
66 | } key_struct; | ||
67 | #endif | ||
68 | } u; | ||
69 | const char *function; | ||
70 | /* this union contains LSM specific data */ | ||
71 | union { | ||
72 | /* SMACK data */ | ||
73 | struct smack_audit_data { | ||
74 | char *subject; | ||
75 | char *object; | ||
76 | char *request; | ||
77 | int result; | ||
78 | } smack_audit_data; | ||
79 | /* SELinux data */ | ||
80 | struct { | ||
81 | u32 ssid; | ||
82 | u32 tsid; | ||
83 | u16 tclass; | ||
84 | u32 requested; | ||
85 | u32 audited; | ||
86 | struct av_decision *avd; | ||
87 | int result; | ||
88 | } selinux_audit_data; | ||
89 | } lsm_priv; | ||
90 | /* these callback will be implemented by a specific LSM */ | ||
91 | void (*lsm_pre_audit)(struct audit_buffer *, void *); | ||
92 | void (*lsm_post_audit)(struct audit_buffer *, void *); | ||
93 | }; | ||
94 | |||
95 | #define v4info fam.v4 | ||
96 | #define v6info fam.v6 | ||
97 | |||
98 | int ipv4_skb_to_auditdata(struct sk_buff *skb, | ||
99 | struct common_audit_data *ad, u8 *proto); | ||
100 | |||
101 | int ipv6_skb_to_auditdata(struct sk_buff *skb, | ||
102 | struct common_audit_data *ad, u8 *proto); | ||
103 | |||
104 | /* Initialize an LSM audit data structure. */ | ||
105 | #define COMMON_AUDIT_DATA_INIT(_d, _t) \ | ||
106 | { memset((_d), 0, sizeof(struct common_audit_data)); \ | ||
107 | (_d)->type = LSM_AUDIT_DATA_##_t; (_d)->function = __func__; } | ||
108 | |||
109 | void common_lsm_audit(struct common_audit_data *a); | ||
110 | |||
111 | #endif | ||
diff --git a/include/linux/magic.h b/include/linux/magic.h index 5b4e28bcb788..927138cf3050 100644 --- a/include/linux/magic.h +++ b/include/linux/magic.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #define DEBUGFS_MAGIC 0x64626720 | 9 | #define DEBUGFS_MAGIC 0x64626720 |
10 | #define SYSFS_MAGIC 0x62656572 | 10 | #define SYSFS_MAGIC 0x62656572 |
11 | #define SECURITYFS_MAGIC 0x73636673 | 11 | #define SECURITYFS_MAGIC 0x73636673 |
12 | #define SELINUX_MAGIC 0xf97cff8c | ||
12 | #define TMPFS_MAGIC 0x01021994 | 13 | #define TMPFS_MAGIC 0x01021994 |
13 | #define SQUASHFS_MAGIC 0x73717368 | 14 | #define SQUASHFS_MAGIC 0x73717368 |
14 | #define EFS_SUPER_MAGIC 0x414A53 | 15 | #define EFS_SUPER_MAGIC 0x414A53 |
diff --git a/include/linux/mm.h b/include/linux/mm.h index 511b09867096..5528ff32512e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -580,12 +580,10 @@ static inline void set_page_links(struct page *page, enum zone_type zone, | |||
580 | */ | 580 | */ |
581 | static inline unsigned long round_hint_to_min(unsigned long hint) | 581 | static inline unsigned long round_hint_to_min(unsigned long hint) |
582 | { | 582 | { |
583 | #ifdef CONFIG_SECURITY | ||
584 | hint &= PAGE_MASK; | 583 | hint &= PAGE_MASK; |
585 | if (((void *)hint != NULL) && | 584 | if (((void *)hint != NULL) && |
586 | (hint < mmap_min_addr)) | 585 | (hint < mmap_min_addr)) |
587 | return PAGE_ALIGN(mmap_min_addr); | 586 | return PAGE_ALIGN(mmap_min_addr); |
588 | #endif | ||
589 | return hint; | 587 | return hint; |
590 | } | 588 | } |
591 | 589 | ||
diff --git a/include/linux/sched.h b/include/linux/sched.h index dbb1043e8656..ff687281f233 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1267,7 +1267,9 @@ struct task_struct { | |||
1267 | * credentials (COW) */ | 1267 | * credentials (COW) */ |
1268 | const struct cred *cred; /* effective (overridable) subjective task | 1268 | const struct cred *cred; /* effective (overridable) subjective task |
1269 | * credentials (COW) */ | 1269 | * credentials (COW) */ |
1270 | struct mutex cred_exec_mutex; /* execve vs ptrace cred calculation mutex */ | 1270 | struct mutex cred_guard_mutex; /* guard against foreign influences on |
1271 | * credential calculations | ||
1272 | * (notably. ptrace) */ | ||
1271 | 1273 | ||
1272 | char comm[TASK_COMM_LEN]; /* executable name excluding path | 1274 | char comm[TASK_COMM_LEN]; /* executable name excluding path |
1273 | - access with [gs]et_task_comm (which lock | 1275 | - access with [gs]et_task_comm (which lock |
@@ -1905,6 +1907,7 @@ extern void sched_dead(struct task_struct *p); | |||
1905 | 1907 | ||
1906 | extern void proc_caches_init(void); | 1908 | extern void proc_caches_init(void); |
1907 | extern void flush_signals(struct task_struct *); | 1909 | extern void flush_signals(struct task_struct *); |
1910 | extern void __flush_signals(struct task_struct *); | ||
1908 | extern void ignore_signals(struct task_struct *); | 1911 | extern void ignore_signals(struct task_struct *); |
1909 | extern void flush_signal_handlers(struct task_struct *, int force_default); | 1912 | extern void flush_signal_handlers(struct task_struct *, int force_default); |
1910 | extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info); | 1913 | extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info); |
diff --git a/include/linux/security.h b/include/linux/security.h index d5fd6163606f..5eff459b3833 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -2197,6 +2197,8 @@ static inline int security_file_mmap(struct file *file, unsigned long reqprot, | |||
2197 | unsigned long addr, | 2197 | unsigned long addr, |
2198 | unsigned long addr_only) | 2198 | unsigned long addr_only) |
2199 | { | 2199 | { |
2200 | if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO)) | ||
2201 | return -EACCES; | ||
2200 | return 0; | 2202 | return 0; |
2201 | } | 2203 | } |
2202 | 2204 | ||
@@ -384,7 +384,6 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) | |||
384 | error = PTR_ERR(file); | 384 | error = PTR_ERR(file); |
385 | if (IS_ERR(file)) | 385 | if (IS_ERR(file)) |
386 | goto no_file; | 386 | goto no_file; |
387 | ima_shm_check(file); | ||
388 | 387 | ||
389 | id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); | 388 | id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); |
390 | if (id < 0) { | 389 | if (id < 0) { |
@@ -891,7 +890,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) | |||
891 | file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations); | 890 | file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations); |
892 | if (!file) | 891 | if (!file) |
893 | goto out_free; | 892 | goto out_free; |
894 | ima_shm_check(file); | 893 | ima_counts_get(file); |
895 | 894 | ||
896 | file->private_data = sfd; | 895 | file->private_data = sfd; |
897 | file->f_mapping = shp->shm_file->f_mapping; | 896 | file->f_mapping = shp->shm_file->f_mapping; |
diff --git a/kernel/cred.c b/kernel/cred.c index 3a039189d707..1bb4d7e5d616 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
@@ -167,7 +167,7 @@ EXPORT_SYMBOL(prepare_creds); | |||
167 | 167 | ||
168 | /* | 168 | /* |
169 | * Prepare credentials for current to perform an execve() | 169 | * Prepare credentials for current to perform an execve() |
170 | * - The caller must hold current->cred_exec_mutex | 170 | * - The caller must hold current->cred_guard_mutex |
171 | */ | 171 | */ |
172 | struct cred *prepare_exec_creds(void) | 172 | struct cred *prepare_exec_creds(void) |
173 | { | 173 | { |
@@ -276,7 +276,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) | |||
276 | struct cred *new; | 276 | struct cred *new; |
277 | int ret; | 277 | int ret; |
278 | 278 | ||
279 | mutex_init(&p->cred_exec_mutex); | 279 | mutex_init(&p->cred_guard_mutex); |
280 | 280 | ||
281 | if ( | 281 | if ( |
282 | #ifdef CONFIG_KEYS | 282 | #ifdef CONFIG_KEYS |
diff --git a/kernel/exit.c b/kernel/exit.c index abf9cf3b95c6..036e8d740169 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -1476,6 +1476,7 @@ static int wait_consider_task(struct task_struct *parent, int ptrace, | |||
1476 | */ | 1476 | */ |
1477 | if (*notask_error) | 1477 | if (*notask_error) |
1478 | *notask_error = ret; | 1478 | *notask_error = ret; |
1479 | return 0; | ||
1479 | } | 1480 | } |
1480 | 1481 | ||
1481 | if (likely(!ptrace) && unlikely(p->ptrace)) { | 1482 | if (likely(!ptrace) && unlikely(p->ptrace)) { |
diff --git a/kernel/module.c b/kernel/module.c index e797812a4d95..cb3887e770e2 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -72,6 +72,9 @@ DEFINE_MUTEX(module_mutex); | |||
72 | EXPORT_SYMBOL_GPL(module_mutex); | 72 | EXPORT_SYMBOL_GPL(module_mutex); |
73 | static LIST_HEAD(modules); | 73 | static LIST_HEAD(modules); |
74 | 74 | ||
75 | /* Block module loading/unloading? */ | ||
76 | int modules_disabled = 0; | ||
77 | |||
75 | /* Waiting for a module to finish initializing? */ | 78 | /* Waiting for a module to finish initializing? */ |
76 | static DECLARE_WAIT_QUEUE_HEAD(module_wq); | 79 | static DECLARE_WAIT_QUEUE_HEAD(module_wq); |
77 | 80 | ||
@@ -777,7 +780,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, | |||
777 | char name[MODULE_NAME_LEN]; | 780 | char name[MODULE_NAME_LEN]; |
778 | int ret, forced = 0; | 781 | int ret, forced = 0; |
779 | 782 | ||
780 | if (!capable(CAP_SYS_MODULE)) | 783 | if (!capable(CAP_SYS_MODULE) || modules_disabled) |
781 | return -EPERM; | 784 | return -EPERM; |
782 | 785 | ||
783 | if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) | 786 | if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) |
@@ -2336,7 +2339,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, | |||
2336 | int ret = 0; | 2339 | int ret = 0; |
2337 | 2340 | ||
2338 | /* Must have permission */ | 2341 | /* Must have permission */ |
2339 | if (!capable(CAP_SYS_MODULE)) | 2342 | if (!capable(CAP_SYS_MODULE) || modules_disabled) |
2340 | return -EPERM; | 2343 | return -EPERM; |
2341 | 2344 | ||
2342 | /* Only one module load at a time, please */ | 2345 | /* Only one module load at a time, please */ |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 42c317874cfa..43a5a3b0be79 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -185,10 +185,11 @@ int ptrace_attach(struct task_struct *task) | |||
185 | if (same_thread_group(task, current)) | 185 | if (same_thread_group(task, current)) |
186 | goto out; | 186 | goto out; |
187 | 187 | ||
188 | /* Protect exec's credential calculations against our interference; | 188 | /* Protect the target's credential calculations against our |
189 | * SUID, SGID and LSM creds get determined differently under ptrace. | 189 | * interference; SUID, SGID and LSM creds get determined differently |
190 | * under ptrace. | ||
190 | */ | 191 | */ |
191 | retval = mutex_lock_interruptible(&task->cred_exec_mutex); | 192 | retval = mutex_lock_interruptible(&task->cred_guard_mutex); |
192 | if (retval < 0) | 193 | if (retval < 0) |
193 | goto out; | 194 | goto out; |
194 | 195 | ||
@@ -232,7 +233,7 @@ repeat: | |||
232 | bad: | 233 | bad: |
233 | write_unlock_irqrestore(&tasklist_lock, flags); | 234 | write_unlock_irqrestore(&tasklist_lock, flags); |
234 | task_unlock(task); | 235 | task_unlock(task); |
235 | mutex_unlock(&task->cred_exec_mutex); | 236 | mutex_unlock(&task->cred_guard_mutex); |
236 | out: | 237 | out: |
237 | return retval; | 238 | return retval; |
238 | } | 239 | } |
diff --git a/kernel/signal.c b/kernel/signal.c index d8034737db4c..d2dd9cf5dcc6 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -249,14 +249,19 @@ void flush_sigqueue(struct sigpending *queue) | |||
249 | /* | 249 | /* |
250 | * Flush all pending signals for a task. | 250 | * Flush all pending signals for a task. |
251 | */ | 251 | */ |
252 | void __flush_signals(struct task_struct *t) | ||
253 | { | ||
254 | clear_tsk_thread_flag(t, TIF_SIGPENDING); | ||
255 | flush_sigqueue(&t->pending); | ||
256 | flush_sigqueue(&t->signal->shared_pending); | ||
257 | } | ||
258 | |||
252 | void flush_signals(struct task_struct *t) | 259 | void flush_signals(struct task_struct *t) |
253 | { | 260 | { |
254 | unsigned long flags; | 261 | unsigned long flags; |
255 | 262 | ||
256 | spin_lock_irqsave(&t->sighand->siglock, flags); | 263 | spin_lock_irqsave(&t->sighand->siglock, flags); |
257 | clear_tsk_thread_flag(t, TIF_SIGPENDING); | 264 | __flush_signals(t); |
258 | flush_sigqueue(&t->pending); | ||
259 | flush_sigqueue(&t->signal->shared_pending); | ||
260 | spin_unlock_irqrestore(&t->sighand->siglock, flags); | 265 | spin_unlock_irqrestore(&t->sighand->siglock, flags); |
261 | } | 266 | } |
262 | 267 | ||
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 6a463716ecbf..944ba03cae19 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -114,6 +114,7 @@ static int ngroups_max = NGROUPS_MAX; | |||
114 | 114 | ||
115 | #ifdef CONFIG_MODULES | 115 | #ifdef CONFIG_MODULES |
116 | extern char modprobe_path[]; | 116 | extern char modprobe_path[]; |
117 | extern int modules_disabled; | ||
117 | #endif | 118 | #endif |
118 | #ifdef CONFIG_CHR_DEV_SG | 119 | #ifdef CONFIG_CHR_DEV_SG |
119 | extern int sg_big_buff; | 120 | extern int sg_big_buff; |
@@ -534,6 +535,17 @@ static struct ctl_table kern_table[] = { | |||
534 | .proc_handler = &proc_dostring, | 535 | .proc_handler = &proc_dostring, |
535 | .strategy = &sysctl_string, | 536 | .strategy = &sysctl_string, |
536 | }, | 537 | }, |
538 | { | ||
539 | .ctl_name = CTL_UNNUMBERED, | ||
540 | .procname = "modules_disabled", | ||
541 | .data = &modules_disabled, | ||
542 | .maxlen = sizeof(int), | ||
543 | .mode = 0644, | ||
544 | /* only handle a transition from default "0" to "1" */ | ||
545 | .proc_handler = &proc_dointvec_minmax, | ||
546 | .extra1 = &one, | ||
547 | .extra2 = &one, | ||
548 | }, | ||
537 | #endif | 549 | #endif |
538 | #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET) | 550 | #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET) |
539 | { | 551 | { |
@@ -1233,7 +1245,6 @@ static struct ctl_table vm_table[] = { | |||
1233 | .strategy = &sysctl_jiffies, | 1245 | .strategy = &sysctl_jiffies, |
1234 | }, | 1246 | }, |
1235 | #endif | 1247 | #endif |
1236 | #ifdef CONFIG_SECURITY | ||
1237 | { | 1248 | { |
1238 | .ctl_name = CTL_UNNUMBERED, | 1249 | .ctl_name = CTL_UNNUMBERED, |
1239 | .procname = "mmap_min_addr", | 1250 | .procname = "mmap_min_addr", |
@@ -1242,7 +1253,6 @@ static struct ctl_table vm_table[] = { | |||
1242 | .mode = 0644, | 1253 | .mode = 0644, |
1243 | .proc_handler = &proc_doulongvec_minmax, | 1254 | .proc_handler = &proc_doulongvec_minmax, |
1244 | }, | 1255 | }, |
1245 | #endif | ||
1246 | #ifdef CONFIG_NUMA | 1256 | #ifdef CONFIG_NUMA |
1247 | { | 1257 | { |
1248 | .ctl_name = CTL_UNNUMBERED, | 1258 | .ctl_name = CTL_UNNUMBERED, |
diff --git a/mm/Kconfig b/mm/Kconfig index c2b57d81e153..71830ba7b986 100644 --- a/mm/Kconfig +++ b/mm/Kconfig | |||
@@ -226,6 +226,25 @@ config HAVE_MLOCKED_PAGE_BIT | |||
226 | config MMU_NOTIFIER | 226 | config MMU_NOTIFIER |
227 | bool | 227 | bool |
228 | 228 | ||
229 | config DEFAULT_MMAP_MIN_ADDR | ||
230 | int "Low address space to protect from user allocation" | ||
231 | default 4096 | ||
232 | help | ||
233 | This is the portion of low virtual memory which should be protected | ||
234 | from userspace allocation. Keeping a user from writing to low pages | ||
235 | can help reduce the impact of kernel NULL pointer bugs. | ||
236 | |||
237 | For most ia64, ppc64 and x86 users with lots of address space | ||
238 | a value of 65536 is reasonable and should cause no problems. | ||
239 | On arm and other archs it should not be higher than 32768. | ||
240 | Programs which use vm86 functionality would either need additional | ||
241 | permissions from either the LSM or the capabilities module or have | ||
242 | this protection disabled. | ||
243 | |||
244 | This value can be changed after boot using the | ||
245 | /proc/sys/vm/mmap_min_addr tunable. | ||
246 | |||
247 | |||
229 | config NOMMU_INITIAL_TRIM_EXCESS | 248 | config NOMMU_INITIAL_TRIM_EXCESS |
230 | int "Turn on mmap() excess space trimming before booting" | 249 | int "Turn on mmap() excess space trimming before booting" |
231 | depends on !MMU | 250 | depends on !MMU |
@@ -87,6 +87,9 @@ int sysctl_overcommit_ratio = 50; /* default is 50% */ | |||
87 | int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; | 87 | int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; |
88 | struct percpu_counter vm_committed_as; | 88 | struct percpu_counter vm_committed_as; |
89 | 89 | ||
90 | /* amount of vm to protect from userspace access */ | ||
91 | unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; | ||
92 | |||
90 | /* | 93 | /* |
91 | * Check that a process has enough memory to allocate a new virtual | 94 | * Check that a process has enough memory to allocate a new virtual |
92 | * mapping. 0 means there is enough memory for the allocation to | 95 | * mapping. 0 means there is enough memory for the allocation to |
diff --git a/mm/nommu.c b/mm/nommu.c index b571ef707428..2fd2ad5da98e 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
@@ -69,6 +69,9 @@ int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT; | |||
69 | int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS; | 69 | int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS; |
70 | int heap_stack_gap = 0; | 70 | int heap_stack_gap = 0; |
71 | 71 | ||
72 | /* amount of vm to protect from userspace access */ | ||
73 | unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; | ||
74 | |||
72 | atomic_long_t mmap_pages_allocated; | 75 | atomic_long_t mmap_pages_allocated; |
73 | 76 | ||
74 | EXPORT_SYMBOL(mem_map); | 77 | EXPORT_SYMBOL(mem_map); |
diff --git a/mm/shmem.c b/mm/shmem.c index b25f95ce3db7..0132fbd45a23 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -2659,6 +2659,7 @@ struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags) | |||
2659 | if (error) | 2659 | if (error) |
2660 | goto close_file; | 2660 | goto close_file; |
2661 | #endif | 2661 | #endif |
2662 | ima_counts_get(file); | ||
2662 | return file; | 2663 | return file; |
2663 | 2664 | ||
2664 | close_file: | 2665 | close_file: |
@@ -2684,7 +2685,6 @@ int shmem_zero_setup(struct vm_area_struct *vma) | |||
2684 | if (IS_ERR(file)) | 2685 | if (IS_ERR(file)) |
2685 | return PTR_ERR(file); | 2686 | return PTR_ERR(file); |
2686 | 2687 | ||
2687 | ima_shm_check(file); | ||
2688 | if (vma->vm_file) | 2688 | if (vma->vm_file) |
2689 | fput(vma->vm_file); | 2689 | fput(vma->vm_file); |
2690 | vma->vm_file = file; | 2690 | vma->vm_file = file; |
diff --git a/security/Kconfig b/security/Kconfig index bb244774e9d7..d23c839038f0 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -110,28 +110,8 @@ config SECURITY_ROOTPLUG | |||
110 | 110 | ||
111 | See <http://www.linuxjournal.com/article.php?sid=6279> for | 111 | See <http://www.linuxjournal.com/article.php?sid=6279> for |
112 | more information about this module. | 112 | more information about this module. |
113 | |||
114 | If you are unsure how to answer this question, answer N. | ||
115 | |||
116 | config SECURITY_DEFAULT_MMAP_MIN_ADDR | ||
117 | int "Low address space to protect from user allocation" | ||
118 | depends on SECURITY | ||
119 | default 0 | ||
120 | help | ||
121 | This is the portion of low virtual memory which should be protected | ||
122 | from userspace allocation. Keeping a user from writing to low pages | ||
123 | can help reduce the impact of kernel NULL pointer bugs. | ||
124 | |||
125 | For most ia64, ppc64 and x86 users with lots of address space | ||
126 | a value of 65536 is reasonable and should cause no problems. | ||
127 | On arm and other archs it should not be higher than 32768. | ||
128 | Programs which use vm86 functionality would either need additional | ||
129 | permissions from either the LSM or the capabilities module or have | ||
130 | this protection disabled. | ||
131 | |||
132 | This value can be changed after boot using the | ||
133 | /proc/sys/vm/mmap_min_addr tunable. | ||
134 | 113 | ||
114 | If you are unsure how to answer this question, answer N. | ||
135 | 115 | ||
136 | source security/selinux/Kconfig | 116 | source security/selinux/Kconfig |
137 | source security/smack/Kconfig | 117 | source security/smack/Kconfig |
diff --git a/security/Makefile b/security/Makefile index fa77021d9778..c67557cdaa85 100644 --- a/security/Makefile +++ b/security/Makefile | |||
@@ -16,6 +16,9 @@ obj-$(CONFIG_SECURITYFS) += inode.o | |||
16 | # Must precede capability.o in order to stack properly. | 16 | # Must precede capability.o in order to stack properly. |
17 | obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o | 17 | obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o |
18 | obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o | 18 | obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o |
19 | ifeq ($(CONFIG_AUDIT),y) | ||
20 | obj-$(CONFIG_SECURITY_SMACK) += lsm_audit.o | ||
21 | endif | ||
19 | obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o | 22 | obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o |
20 | obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o | 23 | obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o |
21 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o | 24 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o |
diff --git a/security/commoncap.c b/security/commoncap.c index beac0258c2a8..48b7e0228fa3 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -28,6 +28,28 @@ | |||
28 | #include <linux/prctl.h> | 28 | #include <linux/prctl.h> |
29 | #include <linux/securebits.h> | 29 | #include <linux/securebits.h> |
30 | 30 | ||
31 | /* | ||
32 | * If a non-root user executes a setuid-root binary in | ||
33 | * !secure(SECURE_NOROOT) mode, then we raise capabilities. | ||
34 | * However if fE is also set, then the intent is for only | ||
35 | * the file capabilities to be applied, and the setuid-root | ||
36 | * bit is left on either to change the uid (plausible) or | ||
37 | * to get full privilege on a kernel without file capabilities | ||
38 | * support. So in that case we do not raise capabilities. | ||
39 | * | ||
40 | * Warn if that happens, once per boot. | ||
41 | */ | ||
42 | static void warn_setuid_and_fcaps_mixed(char *fname) | ||
43 | { | ||
44 | static int warned; | ||
45 | if (!warned) { | ||
46 | printk(KERN_INFO "warning: `%s' has both setuid-root and" | ||
47 | " effective capabilities. Therefore not raising all" | ||
48 | " capabilities.\n", fname); | ||
49 | warned = 1; | ||
50 | } | ||
51 | } | ||
52 | |||
31 | int cap_netlink_send(struct sock *sk, struct sk_buff *skb) | 53 | int cap_netlink_send(struct sock *sk, struct sk_buff *skb) |
32 | { | 54 | { |
33 | NETLINK_CB(skb).eff_cap = current_cap(); | 55 | NETLINK_CB(skb).eff_cap = current_cap(); |
@@ -464,6 +486,15 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) | |||
464 | 486 | ||
465 | if (!issecure(SECURE_NOROOT)) { | 487 | if (!issecure(SECURE_NOROOT)) { |
466 | /* | 488 | /* |
489 | * If the legacy file capability is set, then don't set privs | ||
490 | * for a setuid root binary run by a non-root user. Do set it | ||
491 | * for a root user just to cause least surprise to an admin. | ||
492 | */ | ||
493 | if (effective && new->uid != 0 && new->euid == 0) { | ||
494 | warn_setuid_and_fcaps_mixed(bprm->filename); | ||
495 | goto skip; | ||
496 | } | ||
497 | /* | ||
467 | * To support inheritance of root-permissions and suid-root | 498 | * To support inheritance of root-permissions and suid-root |
468 | * executables under compatibility mode, we override the | 499 | * executables under compatibility mode, we override the |
469 | * capability sets for the file. | 500 | * capability sets for the file. |
@@ -478,6 +509,7 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) | |||
478 | if (new->euid == 0) | 509 | if (new->euid == 0) |
479 | effective = true; | 510 | effective = true; |
480 | } | 511 | } |
512 | skip: | ||
481 | 513 | ||
482 | /* Don't let someone trace a set[ug]id/setpcap binary with the revised | 514 | /* Don't let someone trace a set[ug]id/setpcap binary with the revised |
483 | * credentials unless they have the appropriate permit | 515 | * credentials unless they have the appropriate permit |
diff --git a/security/inode.c b/security/inode.c index f3b91bfbe4cb..f7496c6a022b 100644 --- a/security/inode.c +++ b/security/inode.c | |||
@@ -287,7 +287,7 @@ void securityfs_remove(struct dentry *dentry) | |||
287 | { | 287 | { |
288 | struct dentry *parent; | 288 | struct dentry *parent; |
289 | 289 | ||
290 | if (!dentry) | 290 | if (!dentry || IS_ERR(dentry)) |
291 | return; | 291 | return; |
292 | 292 | ||
293 | parent = dentry->d_parent; | 293 | parent = dentry->d_parent; |
diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c index 1e082bb987be..ff513ff737f5 100644 --- a/security/integrity/ima/ima_audit.c +++ b/security/integrity/ima/ima_audit.c | |||
@@ -22,18 +22,9 @@ static int ima_audit; | |||
22 | static int __init ima_audit_setup(char *str) | 22 | static int __init ima_audit_setup(char *str) |
23 | { | 23 | { |
24 | unsigned long audit; | 24 | unsigned long audit; |
25 | int rc, result = 0; | ||
26 | char *op = "ima_audit"; | ||
27 | char *cause; | ||
28 | 25 | ||
29 | rc = strict_strtoul(str, 0, &audit); | 26 | if (!strict_strtoul(str, 0, &audit)) |
30 | if (rc || audit > 1) | 27 | ima_audit = audit ? 1 : 0; |
31 | result = 1; | ||
32 | else | ||
33 | ima_audit = audit; | ||
34 | cause = ima_audit ? "enabled" : "not_enabled"; | ||
35 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, | ||
36 | op, cause, result, 0); | ||
37 | return 1; | 28 | return 1; |
38 | } | 29 | } |
39 | __setup("ima_audit=", ima_audit_setup); | 30 | __setup("ima_audit=", ima_audit_setup); |
@@ -50,23 +41,14 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, | |||
50 | 41 | ||
51 | ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); | 42 | ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); |
52 | audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u ses=%u", | 43 | audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u ses=%u", |
53 | current->pid, current->cred->uid, | 44 | current->pid, current_cred()->uid, |
54 | audit_get_loginuid(current), | 45 | audit_get_loginuid(current), |
55 | audit_get_sessionid(current)); | 46 | audit_get_sessionid(current)); |
56 | audit_log_task_context(ab); | 47 | audit_log_task_context(ab); |
57 | switch (audit_msgno) { | 48 | audit_log_format(ab, " op="); |
58 | case AUDIT_INTEGRITY_DATA: | 49 | audit_log_string(ab, op); |
59 | case AUDIT_INTEGRITY_METADATA: | 50 | audit_log_format(ab, " cause="); |
60 | case AUDIT_INTEGRITY_PCR: | 51 | audit_log_string(ab, cause); |
61 | case AUDIT_INTEGRITY_STATUS: | ||
62 | audit_log_format(ab, " op=%s cause=%s", op, cause); | ||
63 | break; | ||
64 | case AUDIT_INTEGRITY_HASH: | ||
65 | audit_log_format(ab, " op=%s hash=%s", op, cause); | ||
66 | break; | ||
67 | default: | ||
68 | audit_log_format(ab, " op=%s", op); | ||
69 | } | ||
70 | audit_log_format(ab, " comm="); | 52 | audit_log_format(ab, " comm="); |
71 | audit_log_untrustedstring(ab, current->comm); | 53 | audit_log_untrustedstring(ab, current->comm); |
72 | if (fname) { | 54 | if (fname) { |
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 50d572b74caf..63003a63aaee 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
@@ -103,7 +103,7 @@ int ima_calc_template_hash(int template_len, void *template, char *digest) | |||
103 | return rc; | 103 | return rc; |
104 | } | 104 | } |
105 | 105 | ||
106 | static void ima_pcrread(int idx, u8 *pcr) | 106 | static void __init ima_pcrread(int idx, u8 *pcr) |
107 | { | 107 | { |
108 | if (!ima_used_chip) | 108 | if (!ima_used_chip) |
109 | return; | 109 | return; |
@@ -115,7 +115,7 @@ static void ima_pcrread(int idx, u8 *pcr) | |||
115 | /* | 115 | /* |
116 | * Calculate the boot aggregate hash | 116 | * Calculate the boot aggregate hash |
117 | */ | 117 | */ |
118 | int ima_calc_boot_aggregate(char *digest) | 118 | int __init ima_calc_boot_aggregate(char *digest) |
119 | { | 119 | { |
120 | struct hash_desc desc; | 120 | struct hash_desc desc; |
121 | struct scatterlist sg; | 121 | struct scatterlist sg; |
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index ffbe259700b1..7039b14e1f73 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c | |||
@@ -15,6 +15,7 @@ | |||
15 | * implemenents security file system for reporting | 15 | * implemenents security file system for reporting |
16 | * current measurement list and IMA statistics | 16 | * current measurement list and IMA statistics |
17 | */ | 17 | */ |
18 | #include <linux/fcntl.h> | ||
18 | #include <linux/module.h> | 19 | #include <linux/module.h> |
19 | #include <linux/seq_file.h> | 20 | #include <linux/seq_file.h> |
20 | #include <linux/rculist.h> | 21 | #include <linux/rculist.h> |
@@ -283,6 +284,9 @@ static atomic_t policy_opencount = ATOMIC_INIT(1); | |||
283 | */ | 284 | */ |
284 | int ima_open_policy(struct inode * inode, struct file * filp) | 285 | int ima_open_policy(struct inode * inode, struct file * filp) |
285 | { | 286 | { |
287 | /* No point in being allowed to open it if you aren't going to write */ | ||
288 | if (!(filp->f_flags & O_WRONLY)) | ||
289 | return -EACCES; | ||
286 | if (atomic_dec_and_test(&policy_opencount)) | 290 | if (atomic_dec_and_test(&policy_opencount)) |
287 | return 0; | 291 | return 0; |
288 | return -EBUSY; | 292 | return -EBUSY; |
@@ -315,7 +319,7 @@ static struct file_operations ima_measure_policy_ops = { | |||
315 | .release = ima_release_policy | 319 | .release = ima_release_policy |
316 | }; | 320 | }; |
317 | 321 | ||
318 | int ima_fs_init(void) | 322 | int __init ima_fs_init(void) |
319 | { | 323 | { |
320 | ima_dir = securityfs_create_dir("ima", NULL); | 324 | ima_dir = securityfs_create_dir("ima", NULL); |
321 | if (IS_ERR(ima_dir)) | 325 | if (IS_ERR(ima_dir)) |
@@ -349,7 +353,7 @@ int ima_fs_init(void) | |||
349 | goto out; | 353 | goto out; |
350 | 354 | ||
351 | ima_policy = securityfs_create_file("policy", | 355 | ima_policy = securityfs_create_file("policy", |
352 | S_IRUSR | S_IRGRP | S_IWUSR, | 356 | S_IWUSR, |
353 | ima_dir, NULL, | 357 | ima_dir, NULL, |
354 | &ima_measure_policy_ops); | 358 | &ima_measure_policy_ops); |
355 | if (IS_ERR(ima_policy)) | 359 | if (IS_ERR(ima_policy)) |
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index ec79f1ee992c..b8dd693f8790 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c | |||
@@ -196,7 +196,7 @@ static void init_once(void *foo) | |||
196 | kref_set(&iint->refcount, 1); | 196 | kref_set(&iint->refcount, 1); |
197 | } | 197 | } |
198 | 198 | ||
199 | void ima_iintcache_init(void) | 199 | void __init ima_iintcache_init(void) |
200 | { | 200 | { |
201 | iint_cache = | 201 | iint_cache = |
202 | kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, | 202 | kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, |
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 0b0bb8c978cc..a40da7ae5900 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c | |||
@@ -38,7 +38,7 @@ int ima_used_chip; | |||
38 | * a different value.) Violations add a zero entry to the measurement | 38 | * a different value.) Violations add a zero entry to the measurement |
39 | * list and extend the aggregate PCR value with ff...ff's. | 39 | * list and extend the aggregate PCR value with ff...ff's. |
40 | */ | 40 | */ |
41 | static void ima_add_boot_aggregate(void) | 41 | static void __init ima_add_boot_aggregate(void) |
42 | { | 42 | { |
43 | struct ima_template_entry *entry; | 43 | struct ima_template_entry *entry; |
44 | const char *op = "add_boot_aggregate"; | 44 | const char *op = "add_boot_aggregate"; |
@@ -71,7 +71,7 @@ err_out: | |||
71 | audit_cause, result, 0); | 71 | audit_cause, result, 0); |
72 | } | 72 | } |
73 | 73 | ||
74 | int ima_init(void) | 74 | int __init ima_init(void) |
75 | { | 75 | { |
76 | u8 pcr_i[IMA_DIGEST_SIZE]; | 76 | u8 pcr_i[IMA_DIGEST_SIZE]; |
77 | int rc; | 77 | int rc; |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index f4e7266f5aee..6f611874d10e 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -29,20 +29,8 @@ int ima_initialized; | |||
29 | char *ima_hash = "sha1"; | 29 | char *ima_hash = "sha1"; |
30 | static int __init hash_setup(char *str) | 30 | static int __init hash_setup(char *str) |
31 | { | 31 | { |
32 | const char *op = "hash_setup"; | 32 | if (strncmp(str, "md5", 3) == 0) |
33 | const char *hash = "sha1"; | 33 | ima_hash = "md5"; |
34 | int result = 0; | ||
35 | int audit_info = 0; | ||
36 | |||
37 | if (strncmp(str, "md5", 3) == 0) { | ||
38 | hash = "md5"; | ||
39 | ima_hash = str; | ||
40 | } else if (strncmp(str, "sha1", 4) != 0) { | ||
41 | hash = "invalid_hash_type"; | ||
42 | result = 1; | ||
43 | } | ||
44 | integrity_audit_msg(AUDIT_INTEGRITY_HASH, NULL, NULL, op, hash, | ||
45 | result, audit_info); | ||
46 | return 1; | 34 | return 1; |
47 | } | 35 | } |
48 | __setup("ima_hash=", hash_setup); | 36 | __setup("ima_hash=", hash_setup); |
@@ -128,10 +116,6 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file, | |||
128 | { | 116 | { |
129 | int rc = 0; | 117 | int rc = 0; |
130 | 118 | ||
131 | if (IS_ERR(file)) { | ||
132 | pr_info("%s dentry_open failed\n", filename); | ||
133 | return rc; | ||
134 | } | ||
135 | iint->opencount++; | 119 | iint->opencount++; |
136 | iint->readcount++; | 120 | iint->readcount++; |
137 | 121 | ||
@@ -141,6 +125,15 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file, | |||
141 | return rc; | 125 | return rc; |
142 | } | 126 | } |
143 | 127 | ||
128 | static void ima_update_counts(struct ima_iint_cache *iint, int mask) | ||
129 | { | ||
130 | iint->opencount++; | ||
131 | if ((mask & MAY_WRITE) || (mask == 0)) | ||
132 | iint->writecount++; | ||
133 | else if (mask & (MAY_READ | MAY_EXEC)) | ||
134 | iint->readcount++; | ||
135 | } | ||
136 | |||
144 | /** | 137 | /** |
145 | * ima_path_check - based on policy, collect/store measurement. | 138 | * ima_path_check - based on policy, collect/store measurement. |
146 | * @path: contains a pointer to the path to be measured | 139 | * @path: contains a pointer to the path to be measured |
@@ -156,10 +149,10 @@ static int get_path_measurement(struct ima_iint_cache *iint, struct file *file, | |||
156 | * - Opening a file for read when already open for write, | 149 | * - Opening a file for read when already open for write, |
157 | * could result in a file measurement error. | 150 | * could result in a file measurement error. |
158 | * | 151 | * |
159 | * Return 0 on success, an error code on failure. | 152 | * Always return 0 and audit dentry_open failures. |
160 | * (Based on the results of appraise_measurement().) | 153 | * (Return code will be based upon measurement appraisal.) |
161 | */ | 154 | */ |
162 | int ima_path_check(struct path *path, int mask) | 155 | int ima_path_check(struct path *path, int mask, int update_counts) |
163 | { | 156 | { |
164 | struct inode *inode = path->dentry->d_inode; | 157 | struct inode *inode = path->dentry->d_inode; |
165 | struct ima_iint_cache *iint; | 158 | struct ima_iint_cache *iint; |
@@ -173,11 +166,8 @@ int ima_path_check(struct path *path, int mask) | |||
173 | return 0; | 166 | return 0; |
174 | 167 | ||
175 | mutex_lock(&iint->mutex); | 168 | mutex_lock(&iint->mutex); |
176 | iint->opencount++; | 169 | if (update_counts) |
177 | if ((mask & MAY_WRITE) || (mask == 0)) | 170 | ima_update_counts(iint, mask); |
178 | iint->writecount++; | ||
179 | else if (mask & (MAY_READ | MAY_EXEC)) | ||
180 | iint->readcount++; | ||
181 | 171 | ||
182 | rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK); | 172 | rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK); |
183 | if (rc < 0) | 173 | if (rc < 0) |
@@ -196,7 +186,19 @@ int ima_path_check(struct path *path, int mask) | |||
196 | struct dentry *dentry = dget(path->dentry); | 186 | struct dentry *dentry = dget(path->dentry); |
197 | struct vfsmount *mnt = mntget(path->mnt); | 187 | struct vfsmount *mnt = mntget(path->mnt); |
198 | 188 | ||
199 | file = dentry_open(dentry, mnt, O_RDONLY, current->cred); | 189 | file = dentry_open(dentry, mnt, O_RDONLY | O_LARGEFILE, |
190 | current_cred()); | ||
191 | if (IS_ERR(file)) { | ||
192 | int audit_info = 0; | ||
193 | |||
194 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, | ||
195 | dentry->d_name.name, | ||
196 | "add_measurement", | ||
197 | "dentry_open failed", | ||
198 | 1, audit_info); | ||
199 | file = NULL; | ||
200 | goto out; | ||
201 | } | ||
200 | rc = get_path_measurement(iint, file, dentry->d_name.name); | 202 | rc = get_path_measurement(iint, file, dentry->d_name.name); |
201 | } | 203 | } |
202 | out: | 204 | out: |
@@ -206,6 +208,7 @@ out: | |||
206 | kref_put(&iint->refcount, iint_free); | 208 | kref_put(&iint->refcount, iint_free); |
207 | return 0; | 209 | return 0; |
208 | } | 210 | } |
211 | EXPORT_SYMBOL_GPL(ima_path_check); | ||
209 | 212 | ||
210 | static int process_measurement(struct file *file, const unsigned char *filename, | 213 | static int process_measurement(struct file *file, const unsigned char *filename, |
211 | int mask, int function) | 214 | int mask, int function) |
@@ -234,7 +237,16 @@ out: | |||
234 | return rc; | 237 | return rc; |
235 | } | 238 | } |
236 | 239 | ||
237 | static void opencount_get(struct file *file) | 240 | /* |
241 | * ima_opens_get - increment file counts | ||
242 | * | ||
243 | * - for IPC shm and shmat file. | ||
244 | * - for nfsd exported files. | ||
245 | * | ||
246 | * Increment the counts for these files to prevent unnecessary | ||
247 | * imbalance messages. | ||
248 | */ | ||
249 | void ima_counts_get(struct file *file) | ||
238 | { | 250 | { |
239 | struct inode *inode = file->f_dentry->d_inode; | 251 | struct inode *inode = file->f_dentry->d_inode; |
240 | struct ima_iint_cache *iint; | 252 | struct ima_iint_cache *iint; |
@@ -246,8 +258,14 @@ static void opencount_get(struct file *file) | |||
246 | return; | 258 | return; |
247 | mutex_lock(&iint->mutex); | 259 | mutex_lock(&iint->mutex); |
248 | iint->opencount++; | 260 | iint->opencount++; |
261 | if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | ||
262 | iint->readcount++; | ||
263 | |||
264 | if (file->f_mode & FMODE_WRITE) | ||
265 | iint->writecount++; | ||
249 | mutex_unlock(&iint->mutex); | 266 | mutex_unlock(&iint->mutex); |
250 | } | 267 | } |
268 | EXPORT_SYMBOL_GPL(ima_counts_get); | ||
251 | 269 | ||
252 | /** | 270 | /** |
253 | * ima_file_mmap - based on policy, collect/store measurement. | 271 | * ima_file_mmap - based on policy, collect/store measurement. |
@@ -272,18 +290,6 @@ int ima_file_mmap(struct file *file, unsigned long prot) | |||
272 | return 0; | 290 | return 0; |
273 | } | 291 | } |
274 | 292 | ||
275 | /* | ||
276 | * ima_shm_check - IPC shm and shmat create/fput a file | ||
277 | * | ||
278 | * Maintain the opencount for these files to prevent unnecessary | ||
279 | * imbalance messages. | ||
280 | */ | ||
281 | void ima_shm_check(struct file *file) | ||
282 | { | ||
283 | opencount_get(file); | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | /** | 293 | /** |
288 | * ima_bprm_check - based on policy, collect/store measurement. | 294 | * ima_bprm_check - based on policy, collect/store measurement. |
289 | * @bprm: contains the linux_binprm structure | 295 | * @bprm: contains the linux_binprm structure |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index b5291ad5ef56..e1278399b345 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -45,24 +45,30 @@ struct ima_measure_rule_entry { | |||
45 | } lsm[MAX_LSM_RULES]; | 45 | } lsm[MAX_LSM_RULES]; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | /* Without LSM specific knowledge, the default policy can only be | 48 | /* |
49 | * Without LSM specific knowledge, the default policy can only be | ||
49 | * written in terms of .action, .func, .mask, .fsmagic, and .uid | 50 | * written in terms of .action, .func, .mask, .fsmagic, and .uid |
50 | */ | 51 | */ |
52 | |||
53 | /* | ||
54 | * The minimum rule set to allow for full TCB coverage. Measures all files | ||
55 | * opened or mmap for exec and everything read by root. Dangerous because | ||
56 | * normal users can easily run the machine out of memory simply building | ||
57 | * and running executables. | ||
58 | */ | ||
51 | static struct ima_measure_rule_entry default_rules[] = { | 59 | static struct ima_measure_rule_entry default_rules[] = { |
52 | {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC, | 60 | {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC,.flags = IMA_FSMAGIC}, |
53 | .flags = IMA_FSMAGIC}, | ||
54 | {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, | 61 | {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, |
55 | {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, | 62 | {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, |
56 | {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, | 63 | {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, |
57 | {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC, | 64 | {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, |
58 | .flags = IMA_FSMAGIC}, | 65 | {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, |
59 | {.action = DONT_MEASURE,.fsmagic = 0xF97CFF8C,.flags = IMA_FSMAGIC}, | ||
60 | {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC, | 66 | {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC, |
61 | .flags = IMA_FUNC | IMA_MASK}, | 67 | .flags = IMA_FUNC | IMA_MASK}, |
62 | {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, | 68 | {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, |
63 | .flags = IMA_FUNC | IMA_MASK}, | 69 | .flags = IMA_FUNC | IMA_MASK}, |
64 | {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0, | 70 | {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0, |
65 | .flags = IMA_FUNC | IMA_MASK | IMA_UID} | 71 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, |
66 | }; | 72 | }; |
67 | 73 | ||
68 | static LIST_HEAD(measure_default_rules); | 74 | static LIST_HEAD(measure_default_rules); |
@@ -71,6 +77,14 @@ static struct list_head *ima_measure; | |||
71 | 77 | ||
72 | static DEFINE_MUTEX(ima_measure_mutex); | 78 | static DEFINE_MUTEX(ima_measure_mutex); |
73 | 79 | ||
80 | static bool ima_use_tcb __initdata; | ||
81 | static int __init default_policy_setup(char *str) | ||
82 | { | ||
83 | ima_use_tcb = 1; | ||
84 | return 1; | ||
85 | } | ||
86 | __setup("ima_tcb", default_policy_setup); | ||
87 | |||
74 | /** | 88 | /** |
75 | * ima_match_rules - determine whether an inode matches the measure rule. | 89 | * ima_match_rules - determine whether an inode matches the measure rule. |
76 | * @rule: a pointer to a rule | 90 | * @rule: a pointer to a rule |
@@ -96,7 +110,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, | |||
96 | if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid) | 110 | if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid) |
97 | return false; | 111 | return false; |
98 | for (i = 0; i < MAX_LSM_RULES; i++) { | 112 | for (i = 0; i < MAX_LSM_RULES; i++) { |
99 | int rc; | 113 | int rc = 0; |
100 | u32 osid, sid; | 114 | u32 osid, sid; |
101 | 115 | ||
102 | if (!rule->lsm[i].rule) | 116 | if (!rule->lsm[i].rule) |
@@ -109,7 +123,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, | |||
109 | security_inode_getsecid(inode, &osid); | 123 | security_inode_getsecid(inode, &osid); |
110 | rc = security_filter_rule_match(osid, | 124 | rc = security_filter_rule_match(osid, |
111 | rule->lsm[i].type, | 125 | rule->lsm[i].type, |
112 | AUDIT_EQUAL, | 126 | Audit_equal, |
113 | rule->lsm[i].rule, | 127 | rule->lsm[i].rule, |
114 | NULL); | 128 | NULL); |
115 | break; | 129 | break; |
@@ -119,7 +133,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, | |||
119 | security_task_getsecid(tsk, &sid); | 133 | security_task_getsecid(tsk, &sid); |
120 | rc = security_filter_rule_match(sid, | 134 | rc = security_filter_rule_match(sid, |
121 | rule->lsm[i].type, | 135 | rule->lsm[i].type, |
122 | AUDIT_EQUAL, | 136 | Audit_equal, |
123 | rule->lsm[i].rule, | 137 | rule->lsm[i].rule, |
124 | NULL); | 138 | NULL); |
125 | default: | 139 | default: |
@@ -164,11 +178,17 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask) | |||
164 | * ima_measure points to either the measure_default_rules or the | 178 | * ima_measure points to either the measure_default_rules or the |
165 | * the new measure_policy_rules. | 179 | * the new measure_policy_rules. |
166 | */ | 180 | */ |
167 | void ima_init_policy(void) | 181 | void __init ima_init_policy(void) |
168 | { | 182 | { |
169 | int i; | 183 | int i, entries; |
184 | |||
185 | /* if !ima_use_tcb set entries = 0 so we load NO default rules */ | ||
186 | if (ima_use_tcb) | ||
187 | entries = ARRAY_SIZE(default_rules); | ||
188 | else | ||
189 | entries = 0; | ||
170 | 190 | ||
171 | for (i = 0; i < ARRAY_SIZE(default_rules); i++) | 191 | for (i = 0; i < entries; i++) |
172 | list_add_tail(&default_rules[i].list, &measure_default_rules); | 192 | list_add_tail(&default_rules[i].list, &measure_default_rules); |
173 | ima_measure = &measure_default_rules; | 193 | ima_measure = &measure_default_rules; |
174 | } | 194 | } |
@@ -227,7 +247,7 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, | |||
227 | 247 | ||
228 | entry->lsm[lsm_rule].type = audit_type; | 248 | entry->lsm[lsm_rule].type = audit_type; |
229 | result = security_filter_rule_init(entry->lsm[lsm_rule].type, | 249 | result = security_filter_rule_init(entry->lsm[lsm_rule].type, |
230 | AUDIT_EQUAL, args, | 250 | Audit_equal, args, |
231 | &entry->lsm[lsm_rule].rule); | 251 | &entry->lsm[lsm_rule].rule); |
232 | return result; | 252 | return result; |
233 | } | 253 | } |
diff --git a/security/lsm_audit.c b/security/lsm_audit.c new file mode 100644 index 000000000000..94b868494b31 --- /dev/null +++ b/security/lsm_audit.c | |||
@@ -0,0 +1,386 @@ | |||
1 | /* | ||
2 | * common LSM auditing functions | ||
3 | * | ||
4 | * Based on code written for SELinux by : | ||
5 | * Stephen Smalley, <sds@epoch.ncsc.mil> | ||
6 | * James Morris <jmorris@redhat.com> | ||
7 | * Author : Etienne Basset, <etienne.basset@ensta.org> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2, | ||
11 | * as published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/types.h> | ||
15 | #include <linux/stddef.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <net/sock.h> | ||
20 | #include <linux/un.h> | ||
21 | #include <net/af_unix.h> | ||
22 | #include <linux/audit.h> | ||
23 | #include <linux/ipv6.h> | ||
24 | #include <linux/ip.h> | ||
25 | #include <net/ip.h> | ||
26 | #include <net/ipv6.h> | ||
27 | #include <linux/tcp.h> | ||
28 | #include <linux/udp.h> | ||
29 | #include <linux/dccp.h> | ||
30 | #include <linux/sctp.h> | ||
31 | #include <linux/lsm_audit.h> | ||
32 | |||
33 | /** | ||
34 | * ipv4_skb_to_auditdata : fill auditdata from skb | ||
35 | * @skb : the skb | ||
36 | * @ad : the audit data to fill | ||
37 | * @proto : the layer 4 protocol | ||
38 | * | ||
39 | * return 0 on success | ||
40 | */ | ||
41 | int ipv4_skb_to_auditdata(struct sk_buff *skb, | ||
42 | struct common_audit_data *ad, u8 *proto) | ||
43 | { | ||
44 | int ret = 0; | ||
45 | struct iphdr *ih; | ||
46 | |||
47 | ih = ip_hdr(skb); | ||
48 | if (ih == NULL) | ||
49 | return -EINVAL; | ||
50 | |||
51 | ad->u.net.v4info.saddr = ih->saddr; | ||
52 | ad->u.net.v4info.daddr = ih->daddr; | ||
53 | |||
54 | if (proto) | ||
55 | *proto = ih->protocol; | ||
56 | /* non initial fragment */ | ||
57 | if (ntohs(ih->frag_off) & IP_OFFSET) | ||
58 | return 0; | ||
59 | |||
60 | switch (ih->protocol) { | ||
61 | case IPPROTO_TCP: { | ||
62 | struct tcphdr *th = tcp_hdr(skb); | ||
63 | if (th == NULL) | ||
64 | break; | ||
65 | |||
66 | ad->u.net.sport = th->source; | ||
67 | ad->u.net.dport = th->dest; | ||
68 | break; | ||
69 | } | ||
70 | case IPPROTO_UDP: { | ||
71 | struct udphdr *uh = udp_hdr(skb); | ||
72 | if (uh == NULL) | ||
73 | break; | ||
74 | |||
75 | ad->u.net.sport = uh->source; | ||
76 | ad->u.net.dport = uh->dest; | ||
77 | break; | ||
78 | } | ||
79 | case IPPROTO_DCCP: { | ||
80 | struct dccp_hdr *dh = dccp_hdr(skb); | ||
81 | if (dh == NULL) | ||
82 | break; | ||
83 | |||
84 | ad->u.net.sport = dh->dccph_sport; | ||
85 | ad->u.net.dport = dh->dccph_dport; | ||
86 | break; | ||
87 | } | ||
88 | case IPPROTO_SCTP: { | ||
89 | struct sctphdr *sh = sctp_hdr(skb); | ||
90 | if (sh == NULL) | ||
91 | break; | ||
92 | ad->u.net.sport = sh->source; | ||
93 | ad->u.net.dport = sh->dest; | ||
94 | break; | ||
95 | } | ||
96 | default: | ||
97 | ret = -EINVAL; | ||
98 | } | ||
99 | return ret; | ||
100 | } | ||
101 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
102 | /** | ||
103 | * ipv6_skb_to_auditdata : fill auditdata from skb | ||
104 | * @skb : the skb | ||
105 | * @ad : the audit data to fill | ||
106 | * @proto : the layer 4 protocol | ||
107 | * | ||
108 | * return 0 on success | ||
109 | */ | ||
110 | int ipv6_skb_to_auditdata(struct sk_buff *skb, | ||
111 | struct common_audit_data *ad, u8 *proto) | ||
112 | { | ||
113 | int offset, ret = 0; | ||
114 | struct ipv6hdr *ip6; | ||
115 | u8 nexthdr; | ||
116 | |||
117 | ip6 = ipv6_hdr(skb); | ||
118 | if (ip6 == NULL) | ||
119 | return -EINVAL; | ||
120 | ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr); | ||
121 | ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr); | ||
122 | ret = 0; | ||
123 | /* IPv6 can have several extension header before the Transport header | ||
124 | * skip them */ | ||
125 | offset = skb_network_offset(skb); | ||
126 | offset += sizeof(*ip6); | ||
127 | nexthdr = ip6->nexthdr; | ||
128 | offset = ipv6_skip_exthdr(skb, offset, &nexthdr); | ||
129 | if (offset < 0) | ||
130 | return 0; | ||
131 | if (proto) | ||
132 | *proto = nexthdr; | ||
133 | switch (nexthdr) { | ||
134 | case IPPROTO_TCP: { | ||
135 | struct tcphdr _tcph, *th; | ||
136 | |||
137 | th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); | ||
138 | if (th == NULL) | ||
139 | break; | ||
140 | |||
141 | ad->u.net.sport = th->source; | ||
142 | ad->u.net.dport = th->dest; | ||
143 | break; | ||
144 | } | ||
145 | case IPPROTO_UDP: { | ||
146 | struct udphdr _udph, *uh; | ||
147 | |||
148 | uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); | ||
149 | if (uh == NULL) | ||
150 | break; | ||
151 | |||
152 | ad->u.net.sport = uh->source; | ||
153 | ad->u.net.dport = uh->dest; | ||
154 | break; | ||
155 | } | ||
156 | case IPPROTO_DCCP: { | ||
157 | struct dccp_hdr _dccph, *dh; | ||
158 | |||
159 | dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); | ||
160 | if (dh == NULL) | ||
161 | break; | ||
162 | |||
163 | ad->u.net.sport = dh->dccph_sport; | ||
164 | ad->u.net.dport = dh->dccph_dport; | ||
165 | break; | ||
166 | } | ||
167 | case IPPROTO_SCTP: { | ||
168 | struct sctphdr _sctph, *sh; | ||
169 | |||
170 | sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph); | ||
171 | if (sh == NULL) | ||
172 | break; | ||
173 | ad->u.net.sport = sh->source; | ||
174 | ad->u.net.dport = sh->dest; | ||
175 | break; | ||
176 | } | ||
177 | default: | ||
178 | ret = -EINVAL; | ||
179 | } | ||
180 | return ret; | ||
181 | } | ||
182 | #endif | ||
183 | |||
184 | |||
185 | static inline void print_ipv6_addr(struct audit_buffer *ab, | ||
186 | struct in6_addr *addr, __be16 port, | ||
187 | char *name1, char *name2) | ||
188 | { | ||
189 | if (!ipv6_addr_any(addr)) | ||
190 | audit_log_format(ab, " %s=%pI6", name1, addr); | ||
191 | if (port) | ||
192 | audit_log_format(ab, " %s=%d", name2, ntohs(port)); | ||
193 | } | ||
194 | |||
195 | static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr, | ||
196 | __be16 port, char *name1, char *name2) | ||
197 | { | ||
198 | if (addr) | ||
199 | audit_log_format(ab, " %s=%pI4", name1, &addr); | ||
200 | if (port) | ||
201 | audit_log_format(ab, " %s=%d", name2, ntohs(port)); | ||
202 | } | ||
203 | |||
204 | /** | ||
205 | * dump_common_audit_data - helper to dump common audit data | ||
206 | * @a : common audit data | ||
207 | * | ||
208 | */ | ||
209 | static void dump_common_audit_data(struct audit_buffer *ab, | ||
210 | struct common_audit_data *a) | ||
211 | { | ||
212 | struct inode *inode = NULL; | ||
213 | struct task_struct *tsk = current; | ||
214 | |||
215 | if (a->tsk) | ||
216 | tsk = a->tsk; | ||
217 | if (tsk && tsk->pid) { | ||
218 | audit_log_format(ab, " pid=%d comm=", tsk->pid); | ||
219 | audit_log_untrustedstring(ab, tsk->comm); | ||
220 | } | ||
221 | |||
222 | switch (a->type) { | ||
223 | case LSM_AUDIT_DATA_IPC: | ||
224 | audit_log_format(ab, " key=%d ", a->u.ipc_id); | ||
225 | break; | ||
226 | case LSM_AUDIT_DATA_CAP: | ||
227 | audit_log_format(ab, " capability=%d ", a->u.cap); | ||
228 | break; | ||
229 | case LSM_AUDIT_DATA_FS: | ||
230 | if (a->u.fs.path.dentry) { | ||
231 | struct dentry *dentry = a->u.fs.path.dentry; | ||
232 | if (a->u.fs.path.mnt) { | ||
233 | audit_log_d_path(ab, "path=", &a->u.fs.path); | ||
234 | } else { | ||
235 | audit_log_format(ab, " name="); | ||
236 | audit_log_untrustedstring(ab, | ||
237 | dentry->d_name.name); | ||
238 | } | ||
239 | inode = dentry->d_inode; | ||
240 | } else if (a->u.fs.inode) { | ||
241 | struct dentry *dentry; | ||
242 | inode = a->u.fs.inode; | ||
243 | dentry = d_find_alias(inode); | ||
244 | if (dentry) { | ||
245 | audit_log_format(ab, " name="); | ||
246 | audit_log_untrustedstring(ab, | ||
247 | dentry->d_name.name); | ||
248 | dput(dentry); | ||
249 | } | ||
250 | } | ||
251 | if (inode) | ||
252 | audit_log_format(ab, " dev=%s ino=%lu", | ||
253 | inode->i_sb->s_id, | ||
254 | inode->i_ino); | ||
255 | break; | ||
256 | case LSM_AUDIT_DATA_TASK: | ||
257 | tsk = a->u.tsk; | ||
258 | if (tsk && tsk->pid) { | ||
259 | audit_log_format(ab, " pid=%d comm=", tsk->pid); | ||
260 | audit_log_untrustedstring(ab, tsk->comm); | ||
261 | } | ||
262 | break; | ||
263 | case LSM_AUDIT_DATA_NET: | ||
264 | if (a->u.net.sk) { | ||
265 | struct sock *sk = a->u.net.sk; | ||
266 | struct unix_sock *u; | ||
267 | int len = 0; | ||
268 | char *p = NULL; | ||
269 | |||
270 | switch (sk->sk_family) { | ||
271 | case AF_INET: { | ||
272 | struct inet_sock *inet = inet_sk(sk); | ||
273 | |||
274 | print_ipv4_addr(ab, inet->rcv_saddr, | ||
275 | inet->sport, | ||
276 | "laddr", "lport"); | ||
277 | print_ipv4_addr(ab, inet->daddr, | ||
278 | inet->dport, | ||
279 | "faddr", "fport"); | ||
280 | break; | ||
281 | } | ||
282 | case AF_INET6: { | ||
283 | struct inet_sock *inet = inet_sk(sk); | ||
284 | struct ipv6_pinfo *inet6 = inet6_sk(sk); | ||
285 | |||
286 | print_ipv6_addr(ab, &inet6->rcv_saddr, | ||
287 | inet->sport, | ||
288 | "laddr", "lport"); | ||
289 | print_ipv6_addr(ab, &inet6->daddr, | ||
290 | inet->dport, | ||
291 | "faddr", "fport"); | ||
292 | break; | ||
293 | } | ||
294 | case AF_UNIX: | ||
295 | u = unix_sk(sk); | ||
296 | if (u->dentry) { | ||
297 | struct path path = { | ||
298 | .dentry = u->dentry, | ||
299 | .mnt = u->mnt | ||
300 | }; | ||
301 | audit_log_d_path(ab, "path=", &path); | ||
302 | break; | ||
303 | } | ||
304 | if (!u->addr) | ||
305 | break; | ||
306 | len = u->addr->len-sizeof(short); | ||
307 | p = &u->addr->name->sun_path[0]; | ||
308 | audit_log_format(ab, " path="); | ||
309 | if (*p) | ||
310 | audit_log_untrustedstring(ab, p); | ||
311 | else | ||
312 | audit_log_n_hex(ab, p, len); | ||
313 | break; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | switch (a->u.net.family) { | ||
318 | case AF_INET: | ||
319 | print_ipv4_addr(ab, a->u.net.v4info.saddr, | ||
320 | a->u.net.sport, | ||
321 | "saddr", "src"); | ||
322 | print_ipv4_addr(ab, a->u.net.v4info.daddr, | ||
323 | a->u.net.dport, | ||
324 | "daddr", "dest"); | ||
325 | break; | ||
326 | case AF_INET6: | ||
327 | print_ipv6_addr(ab, &a->u.net.v6info.saddr, | ||
328 | a->u.net.sport, | ||
329 | "saddr", "src"); | ||
330 | print_ipv6_addr(ab, &a->u.net.v6info.daddr, | ||
331 | a->u.net.dport, | ||
332 | "daddr", "dest"); | ||
333 | break; | ||
334 | } | ||
335 | if (a->u.net.netif > 0) { | ||
336 | struct net_device *dev; | ||
337 | |||
338 | /* NOTE: we always use init's namespace */ | ||
339 | dev = dev_get_by_index(&init_net, a->u.net.netif); | ||
340 | if (dev) { | ||
341 | audit_log_format(ab, " netif=%s", dev->name); | ||
342 | dev_put(dev); | ||
343 | } | ||
344 | } | ||
345 | break; | ||
346 | #ifdef CONFIG_KEYS | ||
347 | case LSM_AUDIT_DATA_KEY: | ||
348 | audit_log_format(ab, " key_serial=%u", a->u.key_struct.key); | ||
349 | if (a->u.key_struct.key_desc) { | ||
350 | audit_log_format(ab, " key_desc="); | ||
351 | audit_log_untrustedstring(ab, a->u.key_struct.key_desc); | ||
352 | } | ||
353 | break; | ||
354 | #endif | ||
355 | } /* switch (a->type) */ | ||
356 | } | ||
357 | |||
358 | /** | ||
359 | * common_lsm_audit - generic LSM auditing function | ||
360 | * @a: auxiliary audit data | ||
361 | * | ||
362 | * setup the audit buffer for common security information | ||
363 | * uses callback to print LSM specific information | ||
364 | */ | ||
365 | void common_lsm_audit(struct common_audit_data *a) | ||
366 | { | ||
367 | struct audit_buffer *ab; | ||
368 | |||
369 | if (a == NULL) | ||
370 | return; | ||
371 | /* we use GFP_ATOMIC so we won't sleep */ | ||
372 | ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC); | ||
373 | |||
374 | if (ab == NULL) | ||
375 | return; | ||
376 | |||
377 | if (a->lsm_pre_audit) | ||
378 | a->lsm_pre_audit(ab, a); | ||
379 | |||
380 | dump_common_audit_data(ab, a); | ||
381 | |||
382 | if (a->lsm_post_audit) | ||
383 | a->lsm_post_audit(ab, a); | ||
384 | |||
385 | audit_log_end(ab); | ||
386 | } | ||
diff --git a/security/root_plug.c b/security/root_plug.c index 40fb4f15e27b..2f7ffa67c4d2 100644 --- a/security/root_plug.c +++ b/security/root_plug.c | |||
@@ -71,18 +71,6 @@ static int rootplug_bprm_check_security (struct linux_binprm *bprm) | |||
71 | } | 71 | } |
72 | 72 | ||
73 | static struct security_operations rootplug_security_ops = { | 73 | static struct security_operations rootplug_security_ops = { |
74 | /* Use the capability functions for some of the hooks */ | ||
75 | .ptrace_may_access = cap_ptrace_may_access, | ||
76 | .ptrace_traceme = cap_ptrace_traceme, | ||
77 | .capget = cap_capget, | ||
78 | .capset = cap_capset, | ||
79 | .capable = cap_capable, | ||
80 | |||
81 | .bprm_set_creds = cap_bprm_set_creds, | ||
82 | |||
83 | .task_fix_setuid = cap_task_fix_setuid, | ||
84 | .task_prctl = cap_task_prctl, | ||
85 | |||
86 | .bprm_check_security = rootplug_bprm_check_security, | 74 | .bprm_check_security = rootplug_bprm_check_security, |
87 | }; | 75 | }; |
88 | 76 | ||
diff --git a/security/security.c b/security/security.c index 5284255c5cdf..dc7674fbfc7a 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -26,9 +26,6 @@ extern void security_fixup_ops(struct security_operations *ops); | |||
26 | 26 | ||
27 | struct security_operations *security_ops; /* Initialized to NULL */ | 27 | struct security_operations *security_ops; /* Initialized to NULL */ |
28 | 28 | ||
29 | /* amount of vm to protect from userspace access */ | ||
30 | unsigned long mmap_min_addr = CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR; | ||
31 | |||
32 | static inline int verify(struct security_operations *ops) | 29 | static inline int verify(struct security_operations *ops) |
33 | { | 30 | { |
34 | /* verify the security_operations structure exists */ | 31 | /* verify the security_operations structure exists */ |
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 7f9b5fac8779..b2ab60859832 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -927,7 +927,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
927 | if (denied) { | 927 | if (denied) { |
928 | if (flags & AVC_STRICT) | 928 | if (flags & AVC_STRICT) |
929 | rc = -EACCES; | 929 | rc = -EACCES; |
930 | else if (!selinux_enforcing || security_permissive_sid(ssid)) | 930 | else if (!selinux_enforcing || (avd->flags & AVD_FLAGS_PERMISSIVE)) |
931 | avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, | 931 | avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, |
932 | tsid, tclass, avd->seqno); | 932 | tsid, tclass, avd->seqno); |
933 | else | 933 | else |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2fcad7c33eaf..195906bce266 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -1980,10 +1980,6 @@ static int selinux_sysctl(ctl_table *table, int op) | |||
1980 | u32 tsid, sid; | 1980 | u32 tsid, sid; |
1981 | int rc; | 1981 | int rc; |
1982 | 1982 | ||
1983 | rc = secondary_ops->sysctl(table, op); | ||
1984 | if (rc) | ||
1985 | return rc; | ||
1986 | |||
1987 | sid = current_sid(); | 1983 | sid = current_sid(); |
1988 | 1984 | ||
1989 | rc = selinux_sysctl_get_sid(table, (op == 0001) ? | 1985 | rc = selinux_sysctl_get_sid(table, (op == 0001) ? |
@@ -2375,10 +2371,8 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm) | |||
2375 | { | 2371 | { |
2376 | const struct task_security_struct *tsec = current_security(); | 2372 | const struct task_security_struct *tsec = current_security(); |
2377 | struct itimerval itimer; | 2373 | struct itimerval itimer; |
2378 | struct sighand_struct *psig; | ||
2379 | u32 osid, sid; | 2374 | u32 osid, sid; |
2380 | int rc, i; | 2375 | int rc, i; |
2381 | unsigned long flags; | ||
2382 | 2376 | ||
2383 | osid = tsec->osid; | 2377 | osid = tsec->osid; |
2384 | sid = tsec->sid; | 2378 | sid = tsec->sid; |
@@ -2398,22 +2392,20 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm) | |||
2398 | memset(&itimer, 0, sizeof itimer); | 2392 | memset(&itimer, 0, sizeof itimer); |
2399 | for (i = 0; i < 3; i++) | 2393 | for (i = 0; i < 3; i++) |
2400 | do_setitimer(i, &itimer, NULL); | 2394 | do_setitimer(i, &itimer, NULL); |
2401 | flush_signals(current); | ||
2402 | spin_lock_irq(¤t->sighand->siglock); | 2395 | spin_lock_irq(¤t->sighand->siglock); |
2403 | flush_signal_handlers(current, 1); | 2396 | if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) { |
2404 | sigemptyset(¤t->blocked); | 2397 | __flush_signals(current); |
2405 | recalc_sigpending(); | 2398 | flush_signal_handlers(current, 1); |
2399 | sigemptyset(¤t->blocked); | ||
2400 | } | ||
2406 | spin_unlock_irq(¤t->sighand->siglock); | 2401 | spin_unlock_irq(¤t->sighand->siglock); |
2407 | } | 2402 | } |
2408 | 2403 | ||
2409 | /* Wake up the parent if it is waiting so that it can recheck | 2404 | /* Wake up the parent if it is waiting so that it can recheck |
2410 | * wait permission to the new task SID. */ | 2405 | * wait permission to the new task SID. */ |
2411 | read_lock_irq(&tasklist_lock); | 2406 | read_lock(&tasklist_lock); |
2412 | psig = current->parent->sighand; | 2407 | wake_up_interruptible(¤t->real_parent->signal->wait_chldexit); |
2413 | spin_lock_irqsave(&psig->siglock, flags); | 2408 | read_unlock(&tasklist_lock); |
2414 | wake_up_interruptible(¤t->parent->signal->wait_chldexit); | ||
2415 | spin_unlock_irqrestore(&psig->siglock, flags); | ||
2416 | read_unlock_irq(&tasklist_lock); | ||
2417 | } | 2409 | } |
2418 | 2410 | ||
2419 | /* superblock security operations */ | 2411 | /* superblock security operations */ |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 5c3434f7626f..ca835795a8b3 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -8,14 +8,13 @@ | |||
8 | #ifndef _SELINUX_SECURITY_H_ | 8 | #ifndef _SELINUX_SECURITY_H_ |
9 | #define _SELINUX_SECURITY_H_ | 9 | #define _SELINUX_SECURITY_H_ |
10 | 10 | ||
11 | #include <linux/magic.h> | ||
11 | #include "flask.h" | 12 | #include "flask.h" |
12 | 13 | ||
13 | #define SECSID_NULL 0x00000000 /* unspecified SID */ | 14 | #define SECSID_NULL 0x00000000 /* unspecified SID */ |
14 | #define SECSID_WILD 0xffffffff /* wildcard SID */ | 15 | #define SECSID_WILD 0xffffffff /* wildcard SID */ |
15 | #define SECCLASS_NULL 0x0000 /* no class */ | 16 | #define SECCLASS_NULL 0x0000 /* no class */ |
16 | 17 | ||
17 | #define SELINUX_MAGIC 0xf97cff8c | ||
18 | |||
19 | /* Identify specific policy version changes */ | 18 | /* Identify specific policy version changes */ |
20 | #define POLICYDB_VERSION_BASE 15 | 19 | #define POLICYDB_VERSION_BASE 15 |
21 | #define POLICYDB_VERSION_BOOL 16 | 20 | #define POLICYDB_VERSION_BOOL 16 |
@@ -91,9 +90,11 @@ struct av_decision { | |||
91 | u32 auditallow; | 90 | u32 auditallow; |
92 | u32 auditdeny; | 91 | u32 auditdeny; |
93 | u32 seqno; | 92 | u32 seqno; |
93 | u32 flags; | ||
94 | }; | 94 | }; |
95 | 95 | ||
96 | int security_permissive_sid(u32 sid); | 96 | /* definitions of av_decision.flags */ |
97 | #define AVD_FLAGS_PERMISSIVE 0x0001 | ||
97 | 98 | ||
98 | int security_compute_av(u32 ssid, u32 tsid, | 99 | int security_compute_av(u32 ssid, u32 tsid, |
99 | u16 tclass, u32 requested, | 100 | u16 tclass, u32 requested, |
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index c6875fd3b9d6..dd7cc6de77f9 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c | |||
@@ -112,6 +112,8 @@ static struct nlmsg_perm nlmsg_audit_perms[] = | |||
112 | { AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, | 112 | { AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, |
113 | { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, | 113 | { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, |
114 | { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ }, | 114 | { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ }, |
115 | { AUDIT_TRIM, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, | ||
116 | { AUDIT_MAKE_EQUIV, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, | ||
115 | { AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, | 117 | { AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, |
116 | { AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT }, | 118 | { AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT }, |
117 | }; | 119 | }; |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 2d5136ec3d54..b4fc506e7a87 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -527,10 +527,10 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
527 | goto out2; | 527 | goto out2; |
528 | 528 | ||
529 | length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, | 529 | length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, |
530 | "%x %x %x %x %u", | 530 | "%x %x %x %x %u %x", |
531 | avd.allowed, 0xffffffff, | 531 | avd.allowed, 0xffffffff, |
532 | avd.auditallow, avd.auditdeny, | 532 | avd.auditallow, avd.auditdeny, |
533 | avd.seqno); | 533 | avd.seqno, avd.flags); |
534 | out2: | 534 | out2: |
535 | kfree(tcon); | 535 | kfree(tcon); |
536 | out: | 536 | out: |
@@ -803,10 +803,6 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, | |||
803 | goto out; | 803 | goto out; |
804 | } | 804 | } |
805 | 805 | ||
806 | if (count > PAGE_SIZE) { | ||
807 | ret = -EINVAL; | ||
808 | goto out; | ||
809 | } | ||
810 | page = (char *)get_zeroed_page(GFP_KERNEL); | 806 | page = (char *)get_zeroed_page(GFP_KERNEL); |
811 | if (!page) { | 807 | if (!page) { |
812 | ret = -ENOMEM; | 808 | ret = -ENOMEM; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index deeec6c013ae..500e6f78e115 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -410,6 +410,7 @@ static int context_struct_compute_av(struct context *scontext, | |||
410 | avd->auditallow = 0; | 410 | avd->auditallow = 0; |
411 | avd->auditdeny = 0xffffffff; | 411 | avd->auditdeny = 0xffffffff; |
412 | avd->seqno = latest_granting; | 412 | avd->seqno = latest_granting; |
413 | avd->flags = 0; | ||
413 | 414 | ||
414 | /* | 415 | /* |
415 | * Check for all the invalid cases. | 416 | * Check for all the invalid cases. |
@@ -528,31 +529,6 @@ inval_class: | |||
528 | return 0; | 529 | return 0; |
529 | } | 530 | } |
530 | 531 | ||
531 | /* | ||
532 | * Given a sid find if the type has the permissive flag set | ||
533 | */ | ||
534 | int security_permissive_sid(u32 sid) | ||
535 | { | ||
536 | struct context *context; | ||
537 | u32 type; | ||
538 | int rc; | ||
539 | |||
540 | read_lock(&policy_rwlock); | ||
541 | |||
542 | context = sidtab_search(&sidtab, sid); | ||
543 | BUG_ON(!context); | ||
544 | |||
545 | type = context->type; | ||
546 | /* | ||
547 | * we are intentionally using type here, not type-1, the 0th bit may | ||
548 | * someday indicate that we are globally setting permissive in policy. | ||
549 | */ | ||
550 | rc = ebitmap_get_bit(&policydb.permissive_map, type); | ||
551 | |||
552 | read_unlock(&policy_rwlock); | ||
553 | return rc; | ||
554 | } | ||
555 | |||
556 | static int security_validtrans_handle_fail(struct context *ocontext, | 532 | static int security_validtrans_handle_fail(struct context *ocontext, |
557 | struct context *ncontext, | 533 | struct context *ncontext, |
558 | struct context *tcontext, | 534 | struct context *tcontext, |
@@ -767,6 +743,10 @@ int security_compute_av(u32 ssid, | |||
767 | 743 | ||
768 | rc = context_struct_compute_av(scontext, tcontext, tclass, | 744 | rc = context_struct_compute_av(scontext, tcontext, tclass, |
769 | requested, avd); | 745 | requested, avd); |
746 | |||
747 | /* permissive domain? */ | ||
748 | if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) | ||
749 | avd->flags |= AVD_FLAGS_PERMISSIVE; | ||
770 | out: | 750 | out: |
771 | read_unlock(&policy_rwlock); | 751 | read_unlock(&policy_rwlock); |
772 | return rc; | 752 | return rc; |
diff --git a/security/smack/smack.h b/security/smack/smack.h index 42ef313f9856..243bec175be0 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <net/netlabel.h> | 20 | #include <net/netlabel.h> |
21 | #include <linux/list.h> | 21 | #include <linux/list.h> |
22 | #include <linux/rculist.h> | 22 | #include <linux/rculist.h> |
23 | #include <linux/lsm_audit.h> | ||
23 | 24 | ||
24 | /* | 25 | /* |
25 | * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is | 26 | * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is |
@@ -179,6 +180,20 @@ struct smack_known { | |||
179 | #define MAY_NOT 0 | 180 | #define MAY_NOT 0 |
180 | 181 | ||
181 | /* | 182 | /* |
183 | * Number of access types used by Smack (rwxa) | ||
184 | */ | ||
185 | #define SMK_NUM_ACCESS_TYPE 4 | ||
186 | |||
187 | /* | ||
188 | * Smack audit data; is empty if CONFIG_AUDIT not set | ||
189 | * to save some stack | ||
190 | */ | ||
191 | struct smk_audit_info { | ||
192 | #ifdef CONFIG_AUDIT | ||
193 | struct common_audit_data a; | ||
194 | #endif | ||
195 | }; | ||
196 | /* | ||
182 | * These functions are in smack_lsm.c | 197 | * These functions are in smack_lsm.c |
183 | */ | 198 | */ |
184 | struct inode_smack *new_inode_smack(char *); | 199 | struct inode_smack *new_inode_smack(char *); |
@@ -186,8 +201,8 @@ struct inode_smack *new_inode_smack(char *); | |||
186 | /* | 201 | /* |
187 | * These functions are in smack_access.c | 202 | * These functions are in smack_access.c |
188 | */ | 203 | */ |
189 | int smk_access(char *, char *, int); | 204 | int smk_access(char *, char *, int, struct smk_audit_info *); |
190 | int smk_curacc(char *, u32); | 205 | int smk_curacc(char *, u32, struct smk_audit_info *); |
191 | int smack_to_cipso(const char *, struct smack_cipso *); | 206 | int smack_to_cipso(const char *, struct smack_cipso *); |
192 | void smack_from_cipso(u32, char *, char *); | 207 | void smack_from_cipso(u32, char *, char *); |
193 | char *smack_from_secid(const u32); | 208 | char *smack_from_secid(const u32); |
@@ -237,4 +252,93 @@ static inline char *smk_of_inode(const struct inode *isp) | |||
237 | return sip->smk_inode; | 252 | return sip->smk_inode; |
238 | } | 253 | } |
239 | 254 | ||
255 | /* | ||
256 | * logging functions | ||
257 | */ | ||
258 | #define SMACK_AUDIT_DENIED 0x1 | ||
259 | #define SMACK_AUDIT_ACCEPT 0x2 | ||
260 | extern int log_policy; | ||
261 | |||
262 | void smack_log(char *subject_label, char *object_label, | ||
263 | int request, | ||
264 | int result, struct smk_audit_info *auditdata); | ||
265 | |||
266 | #ifdef CONFIG_AUDIT | ||
267 | |||
268 | /* | ||
269 | * some inline functions to set up audit data | ||
270 | * they do nothing if CONFIG_AUDIT is not set | ||
271 | * | ||
272 | */ | ||
273 | static inline void smk_ad_init(struct smk_audit_info *a, const char *func, | ||
274 | char type) | ||
275 | { | ||
276 | memset(a, 0, sizeof(*a)); | ||
277 | a->a.type = type; | ||
278 | a->a.function = func; | ||
279 | } | ||
280 | |||
281 | static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, | ||
282 | struct task_struct *t) | ||
283 | { | ||
284 | a->a.u.tsk = t; | ||
285 | } | ||
286 | static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a, | ||
287 | struct dentry *d) | ||
288 | { | ||
289 | a->a.u.fs.path.dentry = d; | ||
290 | } | ||
291 | static inline void smk_ad_setfield_u_fs_path_mnt(struct smk_audit_info *a, | ||
292 | struct vfsmount *m) | ||
293 | { | ||
294 | a->a.u.fs.path.mnt = m; | ||
295 | } | ||
296 | static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a, | ||
297 | struct inode *i) | ||
298 | { | ||
299 | a->a.u.fs.inode = i; | ||
300 | } | ||
301 | static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a, | ||
302 | struct path p) | ||
303 | { | ||
304 | a->a.u.fs.path = p; | ||
305 | } | ||
306 | static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a, | ||
307 | struct sock *sk) | ||
308 | { | ||
309 | a->a.u.net.sk = sk; | ||
310 | } | ||
311 | |||
312 | #else /* no AUDIT */ | ||
313 | |||
314 | static inline void smk_ad_init(struct smk_audit_info *a, const char *func, | ||
315 | char type) | ||
316 | { | ||
317 | } | ||
318 | static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, | ||
319 | struct task_struct *t) | ||
320 | { | ||
321 | } | ||
322 | static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a, | ||
323 | struct dentry *d) | ||
324 | { | ||
325 | } | ||
326 | static inline void smk_ad_setfield_u_fs_path_mnt(struct smk_audit_info *a, | ||
327 | struct vfsmount *m) | ||
328 | { | ||
329 | } | ||
330 | static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a, | ||
331 | struct inode *i) | ||
332 | { | ||
333 | } | ||
334 | static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a, | ||
335 | struct path p) | ||
336 | { | ||
337 | } | ||
338 | static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a, | ||
339 | struct sock *sk) | ||
340 | { | ||
341 | } | ||
342 | #endif | ||
343 | |||
240 | #endif /* _SECURITY_SMACK_H */ | 344 | #endif /* _SECURITY_SMACK_H */ |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index ac0a2707f6d4..513dc1aa16dd 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -59,11 +59,18 @@ LIST_HEAD(smack_known_list); | |||
59 | */ | 59 | */ |
60 | static u32 smack_next_secid = 10; | 60 | static u32 smack_next_secid = 10; |
61 | 61 | ||
62 | /* | ||
63 | * what events do we log | ||
64 | * can be overwritten at run-time by /smack/logging | ||
65 | */ | ||
66 | int log_policy = SMACK_AUDIT_DENIED; | ||
67 | |||
62 | /** | 68 | /** |
63 | * smk_access - determine if a subject has a specific access to an object | 69 | * smk_access - determine if a subject has a specific access to an object |
64 | * @subject_label: a pointer to the subject's Smack label | 70 | * @subject_label: a pointer to the subject's Smack label |
65 | * @object_label: a pointer to the object's Smack label | 71 | * @object_label: a pointer to the object's Smack label |
66 | * @request: the access requested, in "MAY" format | 72 | * @request: the access requested, in "MAY" format |
73 | * @a : a pointer to the audit data | ||
67 | * | 74 | * |
68 | * This function looks up the subject/object pair in the | 75 | * This function looks up the subject/object pair in the |
69 | * access rule list and returns 0 if the access is permitted, | 76 | * access rule list and returns 0 if the access is permitted, |
@@ -78,10 +85,12 @@ static u32 smack_next_secid = 10; | |||
78 | * will be on the list, so checking the pointers may be a worthwhile | 85 | * will be on the list, so checking the pointers may be a worthwhile |
79 | * optimization. | 86 | * optimization. |
80 | */ | 87 | */ |
81 | int smk_access(char *subject_label, char *object_label, int request) | 88 | int smk_access(char *subject_label, char *object_label, int request, |
89 | struct smk_audit_info *a) | ||
82 | { | 90 | { |
83 | u32 may = MAY_NOT; | 91 | u32 may = MAY_NOT; |
84 | struct smack_rule *srp; | 92 | struct smack_rule *srp; |
93 | int rc = 0; | ||
85 | 94 | ||
86 | /* | 95 | /* |
87 | * Hardcoded comparisons. | 96 | * Hardcoded comparisons. |
@@ -89,8 +98,10 @@ int smk_access(char *subject_label, char *object_label, int request) | |||
89 | * A star subject can't access any object. | 98 | * A star subject can't access any object. |
90 | */ | 99 | */ |
91 | if (subject_label == smack_known_star.smk_known || | 100 | if (subject_label == smack_known_star.smk_known || |
92 | strcmp(subject_label, smack_known_star.smk_known) == 0) | 101 | strcmp(subject_label, smack_known_star.smk_known) == 0) { |
93 | return -EACCES; | 102 | rc = -EACCES; |
103 | goto out_audit; | ||
104 | } | ||
94 | /* | 105 | /* |
95 | * An internet object can be accessed by any subject. | 106 | * An internet object can be accessed by any subject. |
96 | * Tasks cannot be assigned the internet label. | 107 | * Tasks cannot be assigned the internet label. |
@@ -100,20 +111,20 @@ int smk_access(char *subject_label, char *object_label, int request) | |||
100 | subject_label == smack_known_web.smk_known || | 111 | subject_label == smack_known_web.smk_known || |
101 | strcmp(object_label, smack_known_web.smk_known) == 0 || | 112 | strcmp(object_label, smack_known_web.smk_known) == 0 || |
102 | strcmp(subject_label, smack_known_web.smk_known) == 0) | 113 | strcmp(subject_label, smack_known_web.smk_known) == 0) |
103 | return 0; | 114 | goto out_audit; |
104 | /* | 115 | /* |
105 | * A star object can be accessed by any subject. | 116 | * A star object can be accessed by any subject. |
106 | */ | 117 | */ |
107 | if (object_label == smack_known_star.smk_known || | 118 | if (object_label == smack_known_star.smk_known || |
108 | strcmp(object_label, smack_known_star.smk_known) == 0) | 119 | strcmp(object_label, smack_known_star.smk_known) == 0) |
109 | return 0; | 120 | goto out_audit; |
110 | /* | 121 | /* |
111 | * An object can be accessed in any way by a subject | 122 | * An object can be accessed in any way by a subject |
112 | * with the same label. | 123 | * with the same label. |
113 | */ | 124 | */ |
114 | if (subject_label == object_label || | 125 | if (subject_label == object_label || |
115 | strcmp(subject_label, object_label) == 0) | 126 | strcmp(subject_label, object_label) == 0) |
116 | return 0; | 127 | goto out_audit; |
117 | /* | 128 | /* |
118 | * A hat subject can read any object. | 129 | * A hat subject can read any object. |
119 | * A floor object can be read by any subject. | 130 | * A floor object can be read by any subject. |
@@ -121,10 +132,10 @@ int smk_access(char *subject_label, char *object_label, int request) | |||
121 | if ((request & MAY_ANYREAD) == request) { | 132 | if ((request & MAY_ANYREAD) == request) { |
122 | if (object_label == smack_known_floor.smk_known || | 133 | if (object_label == smack_known_floor.smk_known || |
123 | strcmp(object_label, smack_known_floor.smk_known) == 0) | 134 | strcmp(object_label, smack_known_floor.smk_known) == 0) |
124 | return 0; | 135 | goto out_audit; |
125 | if (subject_label == smack_known_hat.smk_known || | 136 | if (subject_label == smack_known_hat.smk_known || |
126 | strcmp(subject_label, smack_known_hat.smk_known) == 0) | 137 | strcmp(subject_label, smack_known_hat.smk_known) == 0) |
127 | return 0; | 138 | goto out_audit; |
128 | } | 139 | } |
129 | /* | 140 | /* |
130 | * Beyond here an explicit relationship is required. | 141 | * Beyond here an explicit relationship is required. |
@@ -148,28 +159,36 @@ int smk_access(char *subject_label, char *object_label, int request) | |||
148 | * This is a bit map operation. | 159 | * This is a bit map operation. |
149 | */ | 160 | */ |
150 | if ((request & may) == request) | 161 | if ((request & may) == request) |
151 | return 0; | 162 | goto out_audit; |
152 | 163 | ||
153 | return -EACCES; | 164 | rc = -EACCES; |
165 | out_audit: | ||
166 | #ifdef CONFIG_AUDIT | ||
167 | if (a) | ||
168 | smack_log(subject_label, object_label, request, rc, a); | ||
169 | #endif | ||
170 | return rc; | ||
154 | } | 171 | } |
155 | 172 | ||
156 | /** | 173 | /** |
157 | * smk_curacc - determine if current has a specific access to an object | 174 | * smk_curacc - determine if current has a specific access to an object |
158 | * @obj_label: a pointer to the object's Smack label | 175 | * @obj_label: a pointer to the object's Smack label |
159 | * @mode: the access requested, in "MAY" format | 176 | * @mode: the access requested, in "MAY" format |
177 | * @a : common audit data | ||
160 | * | 178 | * |
161 | * This function checks the current subject label/object label pair | 179 | * This function checks the current subject label/object label pair |
162 | * in the access rule list and returns 0 if the access is permitted, | 180 | * in the access rule list and returns 0 if the access is permitted, |
163 | * non zero otherwise. It allows that current may have the capability | 181 | * non zero otherwise. It allows that current may have the capability |
164 | * to override the rules. | 182 | * to override the rules. |
165 | */ | 183 | */ |
166 | int smk_curacc(char *obj_label, u32 mode) | 184 | int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) |
167 | { | 185 | { |
168 | int rc; | 186 | int rc; |
187 | char *sp = current_security(); | ||
169 | 188 | ||
170 | rc = smk_access(current_security(), obj_label, mode); | 189 | rc = smk_access(sp, obj_label, mode, NULL); |
171 | if (rc == 0) | 190 | if (rc == 0) |
172 | return 0; | 191 | goto out_audit; |
173 | 192 | ||
174 | /* | 193 | /* |
175 | * Return if a specific label has been designated as the | 194 | * Return if a specific label has been designated as the |
@@ -177,14 +196,105 @@ int smk_curacc(char *obj_label, u32 mode) | |||
177 | * have that label. | 196 | * have that label. |
178 | */ | 197 | */ |
179 | if (smack_onlycap != NULL && smack_onlycap != current->cred->security) | 198 | if (smack_onlycap != NULL && smack_onlycap != current->cred->security) |
180 | return rc; | 199 | goto out_audit; |
181 | 200 | ||
182 | if (capable(CAP_MAC_OVERRIDE)) | 201 | if (capable(CAP_MAC_OVERRIDE)) |
183 | return 0; | 202 | return 0; |
184 | 203 | ||
204 | out_audit: | ||
205 | #ifdef CONFIG_AUDIT | ||
206 | if (a) | ||
207 | smack_log(sp, obj_label, mode, rc, a); | ||
208 | #endif | ||
185 | return rc; | 209 | return rc; |
186 | } | 210 | } |
187 | 211 | ||
212 | #ifdef CONFIG_AUDIT | ||
213 | /** | ||
214 | * smack_str_from_perm : helper to transalate an int to a | ||
215 | * readable string | ||
216 | * @string : the string to fill | ||
217 | * @access : the int | ||
218 | * | ||
219 | */ | ||
220 | static inline void smack_str_from_perm(char *string, int access) | ||
221 | { | ||
222 | int i = 0; | ||
223 | if (access & MAY_READ) | ||
224 | string[i++] = 'r'; | ||
225 | if (access & MAY_WRITE) | ||
226 | string[i++] = 'w'; | ||
227 | if (access & MAY_EXEC) | ||
228 | string[i++] = 'x'; | ||
229 | if (access & MAY_APPEND) | ||
230 | string[i++] = 'a'; | ||
231 | string[i] = '\0'; | ||
232 | } | ||
233 | /** | ||
234 | * smack_log_callback - SMACK specific information | ||
235 | * will be called by generic audit code | ||
236 | * @ab : the audit_buffer | ||
237 | * @a : audit_data | ||
238 | * | ||
239 | */ | ||
240 | static void smack_log_callback(struct audit_buffer *ab, void *a) | ||
241 | { | ||
242 | struct common_audit_data *ad = a; | ||
243 | struct smack_audit_data *sad = &ad->lsm_priv.smack_audit_data; | ||
244 | audit_log_format(ab, "lsm=SMACK fn=%s action=%s", ad->function, | ||
245 | sad->result ? "denied" : "granted"); | ||
246 | audit_log_format(ab, " subject="); | ||
247 | audit_log_untrustedstring(ab, sad->subject); | ||
248 | audit_log_format(ab, " object="); | ||
249 | audit_log_untrustedstring(ab, sad->object); | ||
250 | audit_log_format(ab, " requested=%s", sad->request); | ||
251 | } | ||
252 | |||
253 | /** | ||
254 | * smack_log - Audit the granting or denial of permissions. | ||
255 | * @subject_label : smack label of the requester | ||
256 | * @object_label : smack label of the object being accessed | ||
257 | * @request: requested permissions | ||
258 | * @result: result from smk_access | ||
259 | * @a: auxiliary audit data | ||
260 | * | ||
261 | * Audit the granting or denial of permissions in accordance | ||
262 | * with the policy. | ||
263 | */ | ||
264 | void smack_log(char *subject_label, char *object_label, int request, | ||
265 | int result, struct smk_audit_info *ad) | ||
266 | { | ||
267 | char request_buffer[SMK_NUM_ACCESS_TYPE + 1]; | ||
268 | struct smack_audit_data *sad; | ||
269 | struct common_audit_data *a = &ad->a; | ||
270 | |||
271 | /* check if we have to log the current event */ | ||
272 | if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0) | ||
273 | return; | ||
274 | if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0) | ||
275 | return; | ||
276 | |||
277 | if (a->function == NULL) | ||
278 | a->function = "unknown"; | ||
279 | |||
280 | /* end preparing the audit data */ | ||
281 | sad = &a->lsm_priv.smack_audit_data; | ||
282 | smack_str_from_perm(request_buffer, request); | ||
283 | sad->subject = subject_label; | ||
284 | sad->object = object_label; | ||
285 | sad->request = request_buffer; | ||
286 | sad->result = result; | ||
287 | a->lsm_pre_audit = smack_log_callback; | ||
288 | |||
289 | common_lsm_audit(a); | ||
290 | } | ||
291 | #else /* #ifdef CONFIG_AUDIT */ | ||
292 | void smack_log(char *subject_label, char *object_label, int request, | ||
293 | int result, struct smk_audit_info *ad) | ||
294 | { | ||
295 | } | ||
296 | #endif | ||
297 | |||
188 | static DEFINE_MUTEX(smack_known_lock); | 298 | static DEFINE_MUTEX(smack_known_lock); |
189 | 299 | ||
190 | /** | 300 | /** |
@@ -209,7 +319,8 @@ struct smack_known *smk_import_entry(const char *string, int len) | |||
209 | if (found) | 319 | if (found) |
210 | smack[i] = '\0'; | 320 | smack[i] = '\0'; |
211 | else if (i >= len || string[i] > '~' || string[i] <= ' ' || | 321 | else if (i >= len || string[i] > '~' || string[i] <= ' ' || |
212 | string[i] == '/') { | 322 | string[i] == '/' || string[i] == '"' || |
323 | string[i] == '\\' || string[i] == '\'') { | ||
213 | smack[i] = '\0'; | 324 | smack[i] = '\0'; |
214 | found = 1; | 325 | found = 1; |
215 | } else | 326 | } else |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 98b3195347ab..0023182078c7 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <net/netlabel.h> | 30 | #include <net/netlabel.h> |
31 | #include <net/cipso_ipv4.h> | 31 | #include <net/cipso_ipv4.h> |
32 | #include <linux/audit.h> | 32 | #include <linux/audit.h> |
33 | |||
34 | #include "smack.h" | 33 | #include "smack.h" |
35 | 34 | ||
36 | #define task_security(task) (task_cred_xxx((task), security)) | 35 | #define task_security(task) (task_cred_xxx((task), security)) |
@@ -103,14 +102,24 @@ struct inode_smack *new_inode_smack(char *smack) | |||
103 | static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode) | 102 | static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode) |
104 | { | 103 | { |
105 | int rc; | 104 | int rc; |
105 | struct smk_audit_info ad; | ||
106 | char *sp, *tsp; | ||
106 | 107 | ||
107 | rc = cap_ptrace_may_access(ctp, mode); | 108 | rc = cap_ptrace_may_access(ctp, mode); |
108 | if (rc != 0) | 109 | if (rc != 0) |
109 | return rc; | 110 | return rc; |
110 | 111 | ||
111 | rc = smk_access(current_security(), task_security(ctp), MAY_READWRITE); | 112 | sp = current_security(); |
113 | tsp = task_security(ctp); | ||
114 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); | ||
115 | smk_ad_setfield_u_tsk(&ad, ctp); | ||
116 | |||
117 | /* we won't log here, because rc can be overriden */ | ||
118 | rc = smk_access(sp, tsp, MAY_READWRITE, NULL); | ||
112 | if (rc != 0 && capable(CAP_MAC_OVERRIDE)) | 119 | if (rc != 0 && capable(CAP_MAC_OVERRIDE)) |
113 | return 0; | 120 | rc = 0; |
121 | |||
122 | smack_log(sp, tsp, MAY_READWRITE, rc, &ad); | ||
114 | return rc; | 123 | return rc; |
115 | } | 124 | } |
116 | 125 | ||
@@ -125,14 +134,24 @@ static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode) | |||
125 | static int smack_ptrace_traceme(struct task_struct *ptp) | 134 | static int smack_ptrace_traceme(struct task_struct *ptp) |
126 | { | 135 | { |
127 | int rc; | 136 | int rc; |
137 | struct smk_audit_info ad; | ||
138 | char *sp, *tsp; | ||
128 | 139 | ||
129 | rc = cap_ptrace_traceme(ptp); | 140 | rc = cap_ptrace_traceme(ptp); |
130 | if (rc != 0) | 141 | if (rc != 0) |
131 | return rc; | 142 | return rc; |
132 | 143 | ||
133 | rc = smk_access(task_security(ptp), current_security(), MAY_READWRITE); | 144 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); |
145 | smk_ad_setfield_u_tsk(&ad, ptp); | ||
146 | |||
147 | sp = current_security(); | ||
148 | tsp = task_security(ptp); | ||
149 | /* we won't log here, because rc can be overriden */ | ||
150 | rc = smk_access(tsp, sp, MAY_READWRITE, NULL); | ||
134 | if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE)) | 151 | if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE)) |
135 | return 0; | 152 | rc = 0; |
153 | |||
154 | smack_log(tsp, sp, MAY_READWRITE, rc, &ad); | ||
136 | return rc; | 155 | return rc; |
137 | } | 156 | } |
138 | 157 | ||
@@ -327,8 +346,14 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
327 | static int smack_sb_statfs(struct dentry *dentry) | 346 | static int smack_sb_statfs(struct dentry *dentry) |
328 | { | 347 | { |
329 | struct superblock_smack *sbp = dentry->d_sb->s_security; | 348 | struct superblock_smack *sbp = dentry->d_sb->s_security; |
349 | int rc; | ||
350 | struct smk_audit_info ad; | ||
351 | |||
352 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
353 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | ||
330 | 354 | ||
331 | return smk_curacc(sbp->smk_floor, MAY_READ); | 355 | rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad); |
356 | return rc; | ||
332 | } | 357 | } |
333 | 358 | ||
334 | /** | 359 | /** |
@@ -346,8 +371,12 @@ static int smack_sb_mount(char *dev_name, struct path *path, | |||
346 | char *type, unsigned long flags, void *data) | 371 | char *type, unsigned long flags, void *data) |
347 | { | 372 | { |
348 | struct superblock_smack *sbp = path->mnt->mnt_sb->s_security; | 373 | struct superblock_smack *sbp = path->mnt->mnt_sb->s_security; |
374 | struct smk_audit_info ad; | ||
375 | |||
376 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
377 | smk_ad_setfield_u_fs_path(&ad, *path); | ||
349 | 378 | ||
350 | return smk_curacc(sbp->smk_floor, MAY_WRITE); | 379 | return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); |
351 | } | 380 | } |
352 | 381 | ||
353 | /** | 382 | /** |
@@ -361,10 +390,14 @@ static int smack_sb_mount(char *dev_name, struct path *path, | |||
361 | static int smack_sb_umount(struct vfsmount *mnt, int flags) | 390 | static int smack_sb_umount(struct vfsmount *mnt, int flags) |
362 | { | 391 | { |
363 | struct superblock_smack *sbp; | 392 | struct superblock_smack *sbp; |
393 | struct smk_audit_info ad; | ||
364 | 394 | ||
365 | sbp = mnt->mnt_sb->s_security; | 395 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); |
396 | smk_ad_setfield_u_fs_path_dentry(&ad, mnt->mnt_mountpoint); | ||
397 | smk_ad_setfield_u_fs_path_mnt(&ad, mnt); | ||
366 | 398 | ||
367 | return smk_curacc(sbp->smk_floor, MAY_WRITE); | 399 | sbp = mnt->mnt_sb->s_security; |
400 | return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); | ||
368 | } | 401 | } |
369 | 402 | ||
370 | /* | 403 | /* |
@@ -441,15 +474,20 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, | |||
441 | static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, | 474 | static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, |
442 | struct dentry *new_dentry) | 475 | struct dentry *new_dentry) |
443 | { | 476 | { |
444 | int rc; | ||
445 | char *isp; | 477 | char *isp; |
478 | struct smk_audit_info ad; | ||
479 | int rc; | ||
480 | |||
481 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
482 | smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); | ||
446 | 483 | ||
447 | isp = smk_of_inode(old_dentry->d_inode); | 484 | isp = smk_of_inode(old_dentry->d_inode); |
448 | rc = smk_curacc(isp, MAY_WRITE); | 485 | rc = smk_curacc(isp, MAY_WRITE, &ad); |
449 | 486 | ||
450 | if (rc == 0 && new_dentry->d_inode != NULL) { | 487 | if (rc == 0 && new_dentry->d_inode != NULL) { |
451 | isp = smk_of_inode(new_dentry->d_inode); | 488 | isp = smk_of_inode(new_dentry->d_inode); |
452 | rc = smk_curacc(isp, MAY_WRITE); | 489 | smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); |
490 | rc = smk_curacc(isp, MAY_WRITE, &ad); | ||
453 | } | 491 | } |
454 | 492 | ||
455 | return rc; | 493 | return rc; |
@@ -466,18 +504,24 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, | |||
466 | static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) | 504 | static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) |
467 | { | 505 | { |
468 | struct inode *ip = dentry->d_inode; | 506 | struct inode *ip = dentry->d_inode; |
507 | struct smk_audit_info ad; | ||
469 | int rc; | 508 | int rc; |
470 | 509 | ||
510 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
511 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | ||
512 | |||
471 | /* | 513 | /* |
472 | * You need write access to the thing you're unlinking | 514 | * You need write access to the thing you're unlinking |
473 | */ | 515 | */ |
474 | rc = smk_curacc(smk_of_inode(ip), MAY_WRITE); | 516 | rc = smk_curacc(smk_of_inode(ip), MAY_WRITE, &ad); |
475 | if (rc == 0) | 517 | if (rc == 0) { |
476 | /* | 518 | /* |
477 | * You also need write access to the containing directory | 519 | * You also need write access to the containing directory |
478 | */ | 520 | */ |
479 | rc = smk_curacc(smk_of_inode(dir), MAY_WRITE); | 521 | smk_ad_setfield_u_fs_path_dentry(&ad, NULL); |
480 | 522 | smk_ad_setfield_u_fs_inode(&ad, dir); | |
523 | rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); | ||
524 | } | ||
481 | return rc; | 525 | return rc; |
482 | } | 526 | } |
483 | 527 | ||
@@ -491,17 +535,24 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) | |||
491 | */ | 535 | */ |
492 | static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) | 536 | static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) |
493 | { | 537 | { |
538 | struct smk_audit_info ad; | ||
494 | int rc; | 539 | int rc; |
495 | 540 | ||
541 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
542 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | ||
543 | |||
496 | /* | 544 | /* |
497 | * You need write access to the thing you're removing | 545 | * You need write access to the thing you're removing |
498 | */ | 546 | */ |
499 | rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); | 547 | rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); |
500 | if (rc == 0) | 548 | if (rc == 0) { |
501 | /* | 549 | /* |
502 | * You also need write access to the containing directory | 550 | * You also need write access to the containing directory |
503 | */ | 551 | */ |
504 | rc = smk_curacc(smk_of_inode(dir), MAY_WRITE); | 552 | smk_ad_setfield_u_fs_path_dentry(&ad, NULL); |
553 | smk_ad_setfield_u_fs_inode(&ad, dir); | ||
554 | rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); | ||
555 | } | ||
505 | 556 | ||
506 | return rc; | 557 | return rc; |
507 | } | 558 | } |
@@ -525,15 +576,19 @@ static int smack_inode_rename(struct inode *old_inode, | |||
525 | { | 576 | { |
526 | int rc; | 577 | int rc; |
527 | char *isp; | 578 | char *isp; |
579 | struct smk_audit_info ad; | ||
580 | |||
581 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
582 | smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); | ||
528 | 583 | ||
529 | isp = smk_of_inode(old_dentry->d_inode); | 584 | isp = smk_of_inode(old_dentry->d_inode); |
530 | rc = smk_curacc(isp, MAY_READWRITE); | 585 | rc = smk_curacc(isp, MAY_READWRITE, &ad); |
531 | 586 | ||
532 | if (rc == 0 && new_dentry->d_inode != NULL) { | 587 | if (rc == 0 && new_dentry->d_inode != NULL) { |
533 | isp = smk_of_inode(new_dentry->d_inode); | 588 | isp = smk_of_inode(new_dentry->d_inode); |
534 | rc = smk_curacc(isp, MAY_READWRITE); | 589 | smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); |
590 | rc = smk_curacc(isp, MAY_READWRITE, &ad); | ||
535 | } | 591 | } |
536 | |||
537 | return rc; | 592 | return rc; |
538 | } | 593 | } |
539 | 594 | ||
@@ -548,13 +603,15 @@ static int smack_inode_rename(struct inode *old_inode, | |||
548 | */ | 603 | */ |
549 | static int smack_inode_permission(struct inode *inode, int mask) | 604 | static int smack_inode_permission(struct inode *inode, int mask) |
550 | { | 605 | { |
606 | struct smk_audit_info ad; | ||
551 | /* | 607 | /* |
552 | * No permission to check. Existence test. Yup, it's there. | 608 | * No permission to check. Existence test. Yup, it's there. |
553 | */ | 609 | */ |
554 | if (mask == 0) | 610 | if (mask == 0) |
555 | return 0; | 611 | return 0; |
556 | 612 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
557 | return smk_curacc(smk_of_inode(inode), mask); | 613 | smk_ad_setfield_u_fs_inode(&ad, inode); |
614 | return smk_curacc(smk_of_inode(inode), mask, &ad); | ||
558 | } | 615 | } |
559 | 616 | ||
560 | /** | 617 | /** |
@@ -566,13 +623,16 @@ static int smack_inode_permission(struct inode *inode, int mask) | |||
566 | */ | 623 | */ |
567 | static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) | 624 | static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) |
568 | { | 625 | { |
626 | struct smk_audit_info ad; | ||
569 | /* | 627 | /* |
570 | * Need to allow for clearing the setuid bit. | 628 | * Need to allow for clearing the setuid bit. |
571 | */ | 629 | */ |
572 | if (iattr->ia_valid & ATTR_FORCE) | 630 | if (iattr->ia_valid & ATTR_FORCE) |
573 | return 0; | 631 | return 0; |
632 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
633 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | ||
574 | 634 | ||
575 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); | 635 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); |
576 | } | 636 | } |
577 | 637 | ||
578 | /** | 638 | /** |
@@ -584,7 +644,12 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) | |||
584 | */ | 644 | */ |
585 | static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | 645 | static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) |
586 | { | 646 | { |
587 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ); | 647 | struct smk_audit_info ad; |
648 | |||
649 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
650 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | ||
651 | smk_ad_setfield_u_fs_path_mnt(&ad, mnt); | ||
652 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); | ||
588 | } | 653 | } |
589 | 654 | ||
590 | /** | 655 | /** |
@@ -602,6 +667,7 @@ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | |||
602 | static int smack_inode_setxattr(struct dentry *dentry, const char *name, | 667 | static int smack_inode_setxattr(struct dentry *dentry, const char *name, |
603 | const void *value, size_t size, int flags) | 668 | const void *value, size_t size, int flags) |
604 | { | 669 | { |
670 | struct smk_audit_info ad; | ||
605 | int rc = 0; | 671 | int rc = 0; |
606 | 672 | ||
607 | if (strcmp(name, XATTR_NAME_SMACK) == 0 || | 673 | if (strcmp(name, XATTR_NAME_SMACK) == 0 || |
@@ -619,8 +685,11 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, | |||
619 | } else | 685 | } else |
620 | rc = cap_inode_setxattr(dentry, name, value, size, flags); | 686 | rc = cap_inode_setxattr(dentry, name, value, size, flags); |
621 | 687 | ||
688 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
689 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | ||
690 | |||
622 | if (rc == 0) | 691 | if (rc == 0) |
623 | rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); | 692 | rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); |
624 | 693 | ||
625 | return rc; | 694 | return rc; |
626 | } | 695 | } |
@@ -672,7 +741,12 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, | |||
672 | */ | 741 | */ |
673 | static int smack_inode_getxattr(struct dentry *dentry, const char *name) | 742 | static int smack_inode_getxattr(struct dentry *dentry, const char *name) |
674 | { | 743 | { |
675 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ); | 744 | struct smk_audit_info ad; |
745 | |||
746 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
747 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | ||
748 | |||
749 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); | ||
676 | } | 750 | } |
677 | 751 | ||
678 | /* | 752 | /* |
@@ -686,6 +760,7 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name) | |||
686 | */ | 760 | */ |
687 | static int smack_inode_removexattr(struct dentry *dentry, const char *name) | 761 | static int smack_inode_removexattr(struct dentry *dentry, const char *name) |
688 | { | 762 | { |
763 | struct smk_audit_info ad; | ||
689 | int rc = 0; | 764 | int rc = 0; |
690 | 765 | ||
691 | if (strcmp(name, XATTR_NAME_SMACK) == 0 || | 766 | if (strcmp(name, XATTR_NAME_SMACK) == 0 || |
@@ -696,8 +771,10 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) | |||
696 | } else | 771 | } else |
697 | rc = cap_inode_removexattr(dentry, name); | 772 | rc = cap_inode_removexattr(dentry, name); |
698 | 773 | ||
774 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
775 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | ||
699 | if (rc == 0) | 776 | if (rc == 0) |
700 | rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); | 777 | rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); |
701 | 778 | ||
702 | return rc; | 779 | return rc; |
703 | } | 780 | } |
@@ -856,12 +933,16 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd, | |||
856 | unsigned long arg) | 933 | unsigned long arg) |
857 | { | 934 | { |
858 | int rc = 0; | 935 | int rc = 0; |
936 | struct smk_audit_info ad; | ||
937 | |||
938 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
939 | smk_ad_setfield_u_fs_path(&ad, file->f_path); | ||
859 | 940 | ||
860 | if (_IOC_DIR(cmd) & _IOC_WRITE) | 941 | if (_IOC_DIR(cmd) & _IOC_WRITE) |
861 | rc = smk_curacc(file->f_security, MAY_WRITE); | 942 | rc = smk_curacc(file->f_security, MAY_WRITE, &ad); |
862 | 943 | ||
863 | if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) | 944 | if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) |
864 | rc = smk_curacc(file->f_security, MAY_READ); | 945 | rc = smk_curacc(file->f_security, MAY_READ, &ad); |
865 | 946 | ||
866 | return rc; | 947 | return rc; |
867 | } | 948 | } |
@@ -875,7 +956,11 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd, | |||
875 | */ | 956 | */ |
876 | static int smack_file_lock(struct file *file, unsigned int cmd) | 957 | static int smack_file_lock(struct file *file, unsigned int cmd) |
877 | { | 958 | { |
878 | return smk_curacc(file->f_security, MAY_WRITE); | 959 | struct smk_audit_info ad; |
960 | |||
961 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
962 | smk_ad_setfield_u_fs_path_dentry(&ad, file->f_path.dentry); | ||
963 | return smk_curacc(file->f_security, MAY_WRITE, &ad); | ||
879 | } | 964 | } |
880 | 965 | ||
881 | /** | 966 | /** |
@@ -889,8 +974,12 @@ static int smack_file_lock(struct file *file, unsigned int cmd) | |||
889 | static int smack_file_fcntl(struct file *file, unsigned int cmd, | 974 | static int smack_file_fcntl(struct file *file, unsigned int cmd, |
890 | unsigned long arg) | 975 | unsigned long arg) |
891 | { | 976 | { |
977 | struct smk_audit_info ad; | ||
892 | int rc; | 978 | int rc; |
893 | 979 | ||
980 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | ||
981 | smk_ad_setfield_u_fs_path(&ad, file->f_path); | ||
982 | |||
894 | switch (cmd) { | 983 | switch (cmd) { |
895 | case F_DUPFD: | 984 | case F_DUPFD: |
896 | case F_GETFD: | 985 | case F_GETFD: |
@@ -898,7 +987,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, | |||
898 | case F_GETLK: | 987 | case F_GETLK: |
899 | case F_GETOWN: | 988 | case F_GETOWN: |
900 | case F_GETSIG: | 989 | case F_GETSIG: |
901 | rc = smk_curacc(file->f_security, MAY_READ); | 990 | rc = smk_curacc(file->f_security, MAY_READ, &ad); |
902 | break; | 991 | break; |
903 | case F_SETFD: | 992 | case F_SETFD: |
904 | case F_SETFL: | 993 | case F_SETFL: |
@@ -906,10 +995,10 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, | |||
906 | case F_SETLKW: | 995 | case F_SETLKW: |
907 | case F_SETOWN: | 996 | case F_SETOWN: |
908 | case F_SETSIG: | 997 | case F_SETSIG: |
909 | rc = smk_curacc(file->f_security, MAY_WRITE); | 998 | rc = smk_curacc(file->f_security, MAY_WRITE, &ad); |
910 | break; | 999 | break; |
911 | default: | 1000 | default: |
912 | rc = smk_curacc(file->f_security, MAY_READWRITE); | 1001 | rc = smk_curacc(file->f_security, MAY_READWRITE, &ad); |
913 | } | 1002 | } |
914 | 1003 | ||
915 | return rc; | 1004 | return rc; |
@@ -944,14 +1033,21 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, | |||
944 | { | 1033 | { |
945 | struct file *file; | 1034 | struct file *file; |
946 | int rc; | 1035 | int rc; |
1036 | char *tsp = tsk->cred->security; | ||
1037 | struct smk_audit_info ad; | ||
947 | 1038 | ||
948 | /* | 1039 | /* |
949 | * struct fown_struct is never outside the context of a struct file | 1040 | * struct fown_struct is never outside the context of a struct file |
950 | */ | 1041 | */ |
951 | file = container_of(fown, struct file, f_owner); | 1042 | file = container_of(fown, struct file, f_owner); |
952 | rc = smk_access(file->f_security, tsk->cred->security, MAY_WRITE); | 1043 | /* we don't log here as rc can be overriden */ |
1044 | rc = smk_access(file->f_security, tsp, MAY_WRITE, NULL); | ||
953 | if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) | 1045 | if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) |
954 | return 0; | 1046 | rc = 0; |
1047 | |||
1048 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); | ||
1049 | smk_ad_setfield_u_tsk(&ad, tsk); | ||
1050 | smack_log(file->f_security, tsp, MAY_WRITE, rc, &ad); | ||
955 | return rc; | 1051 | return rc; |
956 | } | 1052 | } |
957 | 1053 | ||
@@ -964,7 +1060,10 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, | |||
964 | static int smack_file_receive(struct file *file) | 1060 | static int smack_file_receive(struct file *file) |
965 | { | 1061 | { |
966 | int may = 0; | 1062 | int may = 0; |
1063 | struct smk_audit_info ad; | ||
967 | 1064 | ||
1065 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); | ||
1066 | smk_ad_setfield_u_fs_path(&ad, file->f_path); | ||
968 | /* | 1067 | /* |
969 | * This code relies on bitmasks. | 1068 | * This code relies on bitmasks. |
970 | */ | 1069 | */ |
@@ -973,7 +1072,7 @@ static int smack_file_receive(struct file *file) | |||
973 | if (file->f_mode & FMODE_WRITE) | 1072 | if (file->f_mode & FMODE_WRITE) |
974 | may |= MAY_WRITE; | 1073 | may |= MAY_WRITE; |
975 | 1074 | ||
976 | return smk_curacc(file->f_security, may); | 1075 | return smk_curacc(file->f_security, may, &ad); |
977 | } | 1076 | } |
978 | 1077 | ||
979 | /* | 1078 | /* |
@@ -1053,6 +1152,22 @@ static int smack_kernel_create_files_as(struct cred *new, | |||
1053 | } | 1152 | } |
1054 | 1153 | ||
1055 | /** | 1154 | /** |
1155 | * smk_curacc_on_task - helper to log task related access | ||
1156 | * @p: the task object | ||
1157 | * @access : the access requested | ||
1158 | * | ||
1159 | * Return 0 if access is permitted | ||
1160 | */ | ||
1161 | static int smk_curacc_on_task(struct task_struct *p, int access) | ||
1162 | { | ||
1163 | struct smk_audit_info ad; | ||
1164 | |||
1165 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); | ||
1166 | smk_ad_setfield_u_tsk(&ad, p); | ||
1167 | return smk_curacc(task_security(p), access, &ad); | ||
1168 | } | ||
1169 | |||
1170 | /** | ||
1056 | * smack_task_setpgid - Smack check on setting pgid | 1171 | * smack_task_setpgid - Smack check on setting pgid |
1057 | * @p: the task object | 1172 | * @p: the task object |
1058 | * @pgid: unused | 1173 | * @pgid: unused |
@@ -1061,7 +1176,7 @@ static int smack_kernel_create_files_as(struct cred *new, | |||
1061 | */ | 1176 | */ |
1062 | static int smack_task_setpgid(struct task_struct *p, pid_t pgid) | 1177 | static int smack_task_setpgid(struct task_struct *p, pid_t pgid) |
1063 | { | 1178 | { |
1064 | return smk_curacc(task_security(p), MAY_WRITE); | 1179 | return smk_curacc_on_task(p, MAY_WRITE); |
1065 | } | 1180 | } |
1066 | 1181 | ||
1067 | /** | 1182 | /** |
@@ -1072,7 +1187,7 @@ static int smack_task_setpgid(struct task_struct *p, pid_t pgid) | |||
1072 | */ | 1187 | */ |
1073 | static int smack_task_getpgid(struct task_struct *p) | 1188 | static int smack_task_getpgid(struct task_struct *p) |
1074 | { | 1189 | { |
1075 | return smk_curacc(task_security(p), MAY_READ); | 1190 | return smk_curacc_on_task(p, MAY_READ); |
1076 | } | 1191 | } |
1077 | 1192 | ||
1078 | /** | 1193 | /** |
@@ -1083,7 +1198,7 @@ static int smack_task_getpgid(struct task_struct *p) | |||
1083 | */ | 1198 | */ |
1084 | static int smack_task_getsid(struct task_struct *p) | 1199 | static int smack_task_getsid(struct task_struct *p) |
1085 | { | 1200 | { |
1086 | return smk_curacc(task_security(p), MAY_READ); | 1201 | return smk_curacc_on_task(p, MAY_READ); |
1087 | } | 1202 | } |
1088 | 1203 | ||
1089 | /** | 1204 | /** |
@@ -1111,7 +1226,7 @@ static int smack_task_setnice(struct task_struct *p, int nice) | |||
1111 | 1226 | ||
1112 | rc = cap_task_setnice(p, nice); | 1227 | rc = cap_task_setnice(p, nice); |
1113 | if (rc == 0) | 1228 | if (rc == 0) |
1114 | rc = smk_curacc(task_security(p), MAY_WRITE); | 1229 | rc = smk_curacc_on_task(p, MAY_WRITE); |
1115 | return rc; | 1230 | return rc; |
1116 | } | 1231 | } |
1117 | 1232 | ||
@@ -1128,7 +1243,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio) | |||
1128 | 1243 | ||
1129 | rc = cap_task_setioprio(p, ioprio); | 1244 | rc = cap_task_setioprio(p, ioprio); |
1130 | if (rc == 0) | 1245 | if (rc == 0) |
1131 | rc = smk_curacc(task_security(p), MAY_WRITE); | 1246 | rc = smk_curacc_on_task(p, MAY_WRITE); |
1132 | return rc; | 1247 | return rc; |
1133 | } | 1248 | } |
1134 | 1249 | ||
@@ -1140,7 +1255,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio) | |||
1140 | */ | 1255 | */ |
1141 | static int smack_task_getioprio(struct task_struct *p) | 1256 | static int smack_task_getioprio(struct task_struct *p) |
1142 | { | 1257 | { |
1143 | return smk_curacc(task_security(p), MAY_READ); | 1258 | return smk_curacc_on_task(p, MAY_READ); |
1144 | } | 1259 | } |
1145 | 1260 | ||
1146 | /** | 1261 | /** |
@@ -1158,7 +1273,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy, | |||
1158 | 1273 | ||
1159 | rc = cap_task_setscheduler(p, policy, lp); | 1274 | rc = cap_task_setscheduler(p, policy, lp); |
1160 | if (rc == 0) | 1275 | if (rc == 0) |
1161 | rc = smk_curacc(task_security(p), MAY_WRITE); | 1276 | rc = smk_curacc_on_task(p, MAY_WRITE); |
1162 | return rc; | 1277 | return rc; |
1163 | } | 1278 | } |
1164 | 1279 | ||
@@ -1170,7 +1285,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy, | |||
1170 | */ | 1285 | */ |
1171 | static int smack_task_getscheduler(struct task_struct *p) | 1286 | static int smack_task_getscheduler(struct task_struct *p) |
1172 | { | 1287 | { |
1173 | return smk_curacc(task_security(p), MAY_READ); | 1288 | return smk_curacc_on_task(p, MAY_READ); |
1174 | } | 1289 | } |
1175 | 1290 | ||
1176 | /** | 1291 | /** |
@@ -1181,7 +1296,7 @@ static int smack_task_getscheduler(struct task_struct *p) | |||
1181 | */ | 1296 | */ |
1182 | static int smack_task_movememory(struct task_struct *p) | 1297 | static int smack_task_movememory(struct task_struct *p) |
1183 | { | 1298 | { |
1184 | return smk_curacc(task_security(p), MAY_WRITE); | 1299 | return smk_curacc_on_task(p, MAY_WRITE); |
1185 | } | 1300 | } |
1186 | 1301 | ||
1187 | /** | 1302 | /** |
@@ -1199,18 +1314,23 @@ static int smack_task_movememory(struct task_struct *p) | |||
1199 | static int smack_task_kill(struct task_struct *p, struct siginfo *info, | 1314 | static int smack_task_kill(struct task_struct *p, struct siginfo *info, |
1200 | int sig, u32 secid) | 1315 | int sig, u32 secid) |
1201 | { | 1316 | { |
1317 | struct smk_audit_info ad; | ||
1318 | |||
1319 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); | ||
1320 | smk_ad_setfield_u_tsk(&ad, p); | ||
1202 | /* | 1321 | /* |
1203 | * Sending a signal requires that the sender | 1322 | * Sending a signal requires that the sender |
1204 | * can write the receiver. | 1323 | * can write the receiver. |
1205 | */ | 1324 | */ |
1206 | if (secid == 0) | 1325 | if (secid == 0) |
1207 | return smk_curacc(task_security(p), MAY_WRITE); | 1326 | return smk_curacc(task_security(p), MAY_WRITE, &ad); |
1208 | /* | 1327 | /* |
1209 | * If the secid isn't 0 we're dealing with some USB IO | 1328 | * If the secid isn't 0 we're dealing with some USB IO |
1210 | * specific behavior. This is not clean. For one thing | 1329 | * specific behavior. This is not clean. For one thing |
1211 | * we can't take privilege into account. | 1330 | * we can't take privilege into account. |
1212 | */ | 1331 | */ |
1213 | return smk_access(smack_from_secid(secid), task_security(p), MAY_WRITE); | 1332 | return smk_access(smack_from_secid(secid), task_security(p), |
1333 | MAY_WRITE, &ad); | ||
1214 | } | 1334 | } |
1215 | 1335 | ||
1216 | /** | 1336 | /** |
@@ -1221,11 +1341,15 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, | |||
1221 | */ | 1341 | */ |
1222 | static int smack_task_wait(struct task_struct *p) | 1342 | static int smack_task_wait(struct task_struct *p) |
1223 | { | 1343 | { |
1344 | struct smk_audit_info ad; | ||
1345 | char *sp = current_security(); | ||
1346 | char *tsp = task_security(p); | ||
1224 | int rc; | 1347 | int rc; |
1225 | 1348 | ||
1226 | rc = smk_access(current_security(), task_security(p), MAY_WRITE); | 1349 | /* we don't log here, we can be overriden */ |
1350 | rc = smk_access(sp, tsp, MAY_WRITE, NULL); | ||
1227 | if (rc == 0) | 1351 | if (rc == 0) |
1228 | return 0; | 1352 | goto out_log; |
1229 | 1353 | ||
1230 | /* | 1354 | /* |
1231 | * Allow the operation to succeed if either task | 1355 | * Allow the operation to succeed if either task |
@@ -1239,8 +1363,12 @@ static int smack_task_wait(struct task_struct *p) | |||
1239 | * the smack value. | 1363 | * the smack value. |
1240 | */ | 1364 | */ |
1241 | if (capable(CAP_MAC_OVERRIDE) || has_capability(p, CAP_MAC_OVERRIDE)) | 1365 | if (capable(CAP_MAC_OVERRIDE) || has_capability(p, CAP_MAC_OVERRIDE)) |
1242 | return 0; | 1366 | rc = 0; |
1243 | 1367 | /* we log only if we didn't get overriden */ | |
1368 | out_log: | ||
1369 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); | ||
1370 | smk_ad_setfield_u_tsk(&ad, p); | ||
1371 | smack_log(sp, tsp, MAY_WRITE, rc, &ad); | ||
1244 | return rc; | 1372 | return rc; |
1245 | } | 1373 | } |
1246 | 1374 | ||
@@ -1456,12 +1584,19 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) | |||
1456 | int sk_lbl; | 1584 | int sk_lbl; |
1457 | char *hostsp; | 1585 | char *hostsp; |
1458 | struct socket_smack *ssp = sk->sk_security; | 1586 | struct socket_smack *ssp = sk->sk_security; |
1587 | struct smk_audit_info ad; | ||
1459 | 1588 | ||
1460 | rcu_read_lock(); | 1589 | rcu_read_lock(); |
1461 | hostsp = smack_host_label(sap); | 1590 | hostsp = smack_host_label(sap); |
1462 | if (hostsp != NULL) { | 1591 | if (hostsp != NULL) { |
1463 | sk_lbl = SMACK_UNLABELED_SOCKET; | 1592 | sk_lbl = SMACK_UNLABELED_SOCKET; |
1464 | rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE); | 1593 | #ifdef CONFIG_AUDIT |
1594 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); | ||
1595 | ad.a.u.net.family = sap->sin_family; | ||
1596 | ad.a.u.net.dport = sap->sin_port; | ||
1597 | ad.a.u.net.v4info.daddr = sap->sin_addr.s_addr; | ||
1598 | #endif | ||
1599 | rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE, &ad); | ||
1465 | } else { | 1600 | } else { |
1466 | sk_lbl = SMACK_CIPSO_SOCKET; | 1601 | sk_lbl = SMACK_CIPSO_SOCKET; |
1467 | rc = 0; | 1602 | rc = 0; |
@@ -1657,6 +1792,25 @@ static void smack_shm_free_security(struct shmid_kernel *shp) | |||
1657 | } | 1792 | } |
1658 | 1793 | ||
1659 | /** | 1794 | /** |
1795 | * smk_curacc_shm : check if current has access on shm | ||
1796 | * @shp : the object | ||
1797 | * @access : access requested | ||
1798 | * | ||
1799 | * Returns 0 if current has the requested access, error code otherwise | ||
1800 | */ | ||
1801 | static int smk_curacc_shm(struct shmid_kernel *shp, int access) | ||
1802 | { | ||
1803 | char *ssp = smack_of_shm(shp); | ||
1804 | struct smk_audit_info ad; | ||
1805 | |||
1806 | #ifdef CONFIG_AUDIT | ||
1807 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); | ||
1808 | ad.a.u.ipc_id = shp->shm_perm.id; | ||
1809 | #endif | ||
1810 | return smk_curacc(ssp, access, &ad); | ||
1811 | } | ||
1812 | |||
1813 | /** | ||
1660 | * smack_shm_associate - Smack access check for shm | 1814 | * smack_shm_associate - Smack access check for shm |
1661 | * @shp: the object | 1815 | * @shp: the object |
1662 | * @shmflg: access requested | 1816 | * @shmflg: access requested |
@@ -1665,11 +1819,10 @@ static void smack_shm_free_security(struct shmid_kernel *shp) | |||
1665 | */ | 1819 | */ |
1666 | static int smack_shm_associate(struct shmid_kernel *shp, int shmflg) | 1820 | static int smack_shm_associate(struct shmid_kernel *shp, int shmflg) |
1667 | { | 1821 | { |
1668 | char *ssp = smack_of_shm(shp); | ||
1669 | int may; | 1822 | int may; |
1670 | 1823 | ||
1671 | may = smack_flags_to_may(shmflg); | 1824 | may = smack_flags_to_may(shmflg); |
1672 | return smk_curacc(ssp, may); | 1825 | return smk_curacc_shm(shp, may); |
1673 | } | 1826 | } |
1674 | 1827 | ||
1675 | /** | 1828 | /** |
@@ -1681,7 +1834,6 @@ static int smack_shm_associate(struct shmid_kernel *shp, int shmflg) | |||
1681 | */ | 1834 | */ |
1682 | static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd) | 1835 | static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd) |
1683 | { | 1836 | { |
1684 | char *ssp; | ||
1685 | int may; | 1837 | int may; |
1686 | 1838 | ||
1687 | switch (cmd) { | 1839 | switch (cmd) { |
@@ -1704,9 +1856,7 @@ static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd) | |||
1704 | default: | 1856 | default: |
1705 | return -EINVAL; | 1857 | return -EINVAL; |
1706 | } | 1858 | } |
1707 | 1859 | return smk_curacc_shm(shp, may); | |
1708 | ssp = smack_of_shm(shp); | ||
1709 | return smk_curacc(ssp, may); | ||
1710 | } | 1860 | } |
1711 | 1861 | ||
1712 | /** | 1862 | /** |
@@ -1720,11 +1870,10 @@ static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd) | |||
1720 | static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, | 1870 | static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, |
1721 | int shmflg) | 1871 | int shmflg) |
1722 | { | 1872 | { |
1723 | char *ssp = smack_of_shm(shp); | ||
1724 | int may; | 1873 | int may; |
1725 | 1874 | ||
1726 | may = smack_flags_to_may(shmflg); | 1875 | may = smack_flags_to_may(shmflg); |
1727 | return smk_curacc(ssp, may); | 1876 | return smk_curacc_shm(shp, may); |
1728 | } | 1877 | } |
1729 | 1878 | ||
1730 | /** | 1879 | /** |
@@ -1766,6 +1915,25 @@ static void smack_sem_free_security(struct sem_array *sma) | |||
1766 | } | 1915 | } |
1767 | 1916 | ||
1768 | /** | 1917 | /** |
1918 | * smk_curacc_sem : check if current has access on sem | ||
1919 | * @sma : the object | ||
1920 | * @access : access requested | ||
1921 | * | ||
1922 | * Returns 0 if current has the requested access, error code otherwise | ||
1923 | */ | ||
1924 | static int smk_curacc_sem(struct sem_array *sma, int access) | ||
1925 | { | ||
1926 | char *ssp = smack_of_sem(sma); | ||
1927 | struct smk_audit_info ad; | ||
1928 | |||
1929 | #ifdef CONFIG_AUDIT | ||
1930 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); | ||
1931 | ad.a.u.ipc_id = sma->sem_perm.id; | ||
1932 | #endif | ||
1933 | return smk_curacc(ssp, access, &ad); | ||
1934 | } | ||
1935 | |||
1936 | /** | ||
1769 | * smack_sem_associate - Smack access check for sem | 1937 | * smack_sem_associate - Smack access check for sem |
1770 | * @sma: the object | 1938 | * @sma: the object |
1771 | * @semflg: access requested | 1939 | * @semflg: access requested |
@@ -1774,11 +1942,10 @@ static void smack_sem_free_security(struct sem_array *sma) | |||
1774 | */ | 1942 | */ |
1775 | static int smack_sem_associate(struct sem_array *sma, int semflg) | 1943 | static int smack_sem_associate(struct sem_array *sma, int semflg) |
1776 | { | 1944 | { |
1777 | char *ssp = smack_of_sem(sma); | ||
1778 | int may; | 1945 | int may; |
1779 | 1946 | ||
1780 | may = smack_flags_to_may(semflg); | 1947 | may = smack_flags_to_may(semflg); |
1781 | return smk_curacc(ssp, may); | 1948 | return smk_curacc_sem(sma, may); |
1782 | } | 1949 | } |
1783 | 1950 | ||
1784 | /** | 1951 | /** |
@@ -1790,7 +1957,6 @@ static int smack_sem_associate(struct sem_array *sma, int semflg) | |||
1790 | */ | 1957 | */ |
1791 | static int smack_sem_semctl(struct sem_array *sma, int cmd) | 1958 | static int smack_sem_semctl(struct sem_array *sma, int cmd) |
1792 | { | 1959 | { |
1793 | char *ssp; | ||
1794 | int may; | 1960 | int may; |
1795 | 1961 | ||
1796 | switch (cmd) { | 1962 | switch (cmd) { |
@@ -1819,8 +1985,7 @@ static int smack_sem_semctl(struct sem_array *sma, int cmd) | |||
1819 | return -EINVAL; | 1985 | return -EINVAL; |
1820 | } | 1986 | } |
1821 | 1987 | ||
1822 | ssp = smack_of_sem(sma); | 1988 | return smk_curacc_sem(sma, may); |
1823 | return smk_curacc(ssp, may); | ||
1824 | } | 1989 | } |
1825 | 1990 | ||
1826 | /** | 1991 | /** |
@@ -1837,9 +2002,7 @@ static int smack_sem_semctl(struct sem_array *sma, int cmd) | |||
1837 | static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops, | 2002 | static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops, |
1838 | unsigned nsops, int alter) | 2003 | unsigned nsops, int alter) |
1839 | { | 2004 | { |
1840 | char *ssp = smack_of_sem(sma); | 2005 | return smk_curacc_sem(sma, MAY_READWRITE); |
1841 | |||
1842 | return smk_curacc(ssp, MAY_READWRITE); | ||
1843 | } | 2006 | } |
1844 | 2007 | ||
1845 | /** | 2008 | /** |
@@ -1881,6 +2044,25 @@ static char *smack_of_msq(struct msg_queue *msq) | |||
1881 | } | 2044 | } |
1882 | 2045 | ||
1883 | /** | 2046 | /** |
2047 | * smk_curacc_msq : helper to check if current has access on msq | ||
2048 | * @msq : the msq | ||
2049 | * @access : access requested | ||
2050 | * | ||
2051 | * return 0 if current has access, error otherwise | ||
2052 | */ | ||
2053 | static int smk_curacc_msq(struct msg_queue *msq, int access) | ||
2054 | { | ||
2055 | char *msp = smack_of_msq(msq); | ||
2056 | struct smk_audit_info ad; | ||
2057 | |||
2058 | #ifdef CONFIG_AUDIT | ||
2059 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); | ||
2060 | ad.a.u.ipc_id = msq->q_perm.id; | ||
2061 | #endif | ||
2062 | return smk_curacc(msp, access, &ad); | ||
2063 | } | ||
2064 | |||
2065 | /** | ||
1884 | * smack_msg_queue_associate - Smack access check for msg_queue | 2066 | * smack_msg_queue_associate - Smack access check for msg_queue |
1885 | * @msq: the object | 2067 | * @msq: the object |
1886 | * @msqflg: access requested | 2068 | * @msqflg: access requested |
@@ -1889,11 +2071,10 @@ static char *smack_of_msq(struct msg_queue *msq) | |||
1889 | */ | 2071 | */ |
1890 | static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg) | 2072 | static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg) |
1891 | { | 2073 | { |
1892 | char *msp = smack_of_msq(msq); | ||
1893 | int may; | 2074 | int may; |
1894 | 2075 | ||
1895 | may = smack_flags_to_may(msqflg); | 2076 | may = smack_flags_to_may(msqflg); |
1896 | return smk_curacc(msp, may); | 2077 | return smk_curacc_msq(msq, may); |
1897 | } | 2078 | } |
1898 | 2079 | ||
1899 | /** | 2080 | /** |
@@ -1905,7 +2086,6 @@ static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg) | |||
1905 | */ | 2086 | */ |
1906 | static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd) | 2087 | static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd) |
1907 | { | 2088 | { |
1908 | char *msp; | ||
1909 | int may; | 2089 | int may; |
1910 | 2090 | ||
1911 | switch (cmd) { | 2091 | switch (cmd) { |
@@ -1927,8 +2107,7 @@ static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd) | |||
1927 | return -EINVAL; | 2107 | return -EINVAL; |
1928 | } | 2108 | } |
1929 | 2109 | ||
1930 | msp = smack_of_msq(msq); | 2110 | return smk_curacc_msq(msq, may); |
1931 | return smk_curacc(msp, may); | ||
1932 | } | 2111 | } |
1933 | 2112 | ||
1934 | /** | 2113 | /** |
@@ -1942,11 +2121,10 @@ static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd) | |||
1942 | static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, | 2121 | static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, |
1943 | int msqflg) | 2122 | int msqflg) |
1944 | { | 2123 | { |
1945 | char *msp = smack_of_msq(msq); | 2124 | int may; |
1946 | int rc; | ||
1947 | 2125 | ||
1948 | rc = smack_flags_to_may(msqflg); | 2126 | may = smack_flags_to_may(msqflg); |
1949 | return smk_curacc(msp, rc); | 2127 | return smk_curacc_msq(msq, may); |
1950 | } | 2128 | } |
1951 | 2129 | ||
1952 | /** | 2130 | /** |
@@ -1962,9 +2140,7 @@ static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, | |||
1962 | static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, | 2140 | static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, |
1963 | struct task_struct *target, long type, int mode) | 2141 | struct task_struct *target, long type, int mode) |
1964 | { | 2142 | { |
1965 | char *msp = smack_of_msq(msq); | 2143 | return smk_curacc_msq(msq, MAY_READWRITE); |
1966 | |||
1967 | return smk_curacc(msp, MAY_READWRITE); | ||
1968 | } | 2144 | } |
1969 | 2145 | ||
1970 | /** | 2146 | /** |
@@ -1977,10 +2153,14 @@ static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, | |||
1977 | static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) | 2153 | static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) |
1978 | { | 2154 | { |
1979 | char *isp = ipp->security; | 2155 | char *isp = ipp->security; |
1980 | int may; | 2156 | int may = smack_flags_to_may(flag); |
2157 | struct smk_audit_info ad; | ||
1981 | 2158 | ||
1982 | may = smack_flags_to_may(flag); | 2159 | #ifdef CONFIG_AUDIT |
1983 | return smk_curacc(isp, may); | 2160 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); |
2161 | ad.a.u.ipc_id = ipp->id; | ||
2162 | #endif | ||
2163 | return smk_curacc(isp, may, &ad); | ||
1984 | } | 2164 | } |
1985 | 2165 | ||
1986 | /** | 2166 | /** |
@@ -2239,8 +2419,12 @@ static int smack_unix_stream_connect(struct socket *sock, | |||
2239 | { | 2419 | { |
2240 | struct inode *sp = SOCK_INODE(sock); | 2420 | struct inode *sp = SOCK_INODE(sock); |
2241 | struct inode *op = SOCK_INODE(other); | 2421 | struct inode *op = SOCK_INODE(other); |
2422 | struct smk_audit_info ad; | ||
2242 | 2423 | ||
2243 | return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_READWRITE); | 2424 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); |
2425 | smk_ad_setfield_u_net_sk(&ad, other->sk); | ||
2426 | return smk_access(smk_of_inode(sp), smk_of_inode(op), | ||
2427 | MAY_READWRITE, &ad); | ||
2244 | } | 2428 | } |
2245 | 2429 | ||
2246 | /** | 2430 | /** |
@@ -2255,8 +2439,11 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) | |||
2255 | { | 2439 | { |
2256 | struct inode *sp = SOCK_INODE(sock); | 2440 | struct inode *sp = SOCK_INODE(sock); |
2257 | struct inode *op = SOCK_INODE(other); | 2441 | struct inode *op = SOCK_INODE(other); |
2442 | struct smk_audit_info ad; | ||
2258 | 2443 | ||
2259 | return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE); | 2444 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); |
2445 | smk_ad_setfield_u_net_sk(&ad, other->sk); | ||
2446 | return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE, &ad); | ||
2260 | } | 2447 | } |
2261 | 2448 | ||
2262 | /** | 2449 | /** |
@@ -2371,7 +2558,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
2371 | char smack[SMK_LABELLEN]; | 2558 | char smack[SMK_LABELLEN]; |
2372 | char *csp; | 2559 | char *csp; |
2373 | int rc; | 2560 | int rc; |
2374 | 2561 | struct smk_audit_info ad; | |
2375 | if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) | 2562 | if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) |
2376 | return 0; | 2563 | return 0; |
2377 | 2564 | ||
@@ -2389,13 +2576,19 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
2389 | 2576 | ||
2390 | netlbl_secattr_destroy(&secattr); | 2577 | netlbl_secattr_destroy(&secattr); |
2391 | 2578 | ||
2579 | #ifdef CONFIG_AUDIT | ||
2580 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); | ||
2581 | ad.a.u.net.family = sk->sk_family; | ||
2582 | ad.a.u.net.netif = skb->iif; | ||
2583 | ipv4_skb_to_auditdata(skb, &ad.a, NULL); | ||
2584 | #endif | ||
2392 | /* | 2585 | /* |
2393 | * Receiving a packet requires that the other end | 2586 | * Receiving a packet requires that the other end |
2394 | * be able to write here. Read access is not required. | 2587 | * be able to write here. Read access is not required. |
2395 | * This is the simplist possible security model | 2588 | * This is the simplist possible security model |
2396 | * for networking. | 2589 | * for networking. |
2397 | */ | 2590 | */ |
2398 | rc = smk_access(csp, ssp->smk_in, MAY_WRITE); | 2591 | rc = smk_access(csp, ssp->smk_in, MAY_WRITE, &ad); |
2399 | if (rc != 0) | 2592 | if (rc != 0) |
2400 | netlbl_skbuff_err(skb, rc, 0); | 2593 | netlbl_skbuff_err(skb, rc, 0); |
2401 | return rc; | 2594 | return rc; |
@@ -2524,6 +2717,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
2524 | struct iphdr *hdr; | 2717 | struct iphdr *hdr; |
2525 | char smack[SMK_LABELLEN]; | 2718 | char smack[SMK_LABELLEN]; |
2526 | int rc; | 2719 | int rc; |
2720 | struct smk_audit_info ad; | ||
2527 | 2721 | ||
2528 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ | 2722 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ |
2529 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | 2723 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) |
@@ -2537,11 +2731,17 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
2537 | strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN); | 2731 | strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN); |
2538 | netlbl_secattr_destroy(&secattr); | 2732 | netlbl_secattr_destroy(&secattr); |
2539 | 2733 | ||
2734 | #ifdef CONFIG_AUDIT | ||
2735 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); | ||
2736 | ad.a.u.net.family = family; | ||
2737 | ad.a.u.net.netif = skb->iif; | ||
2738 | ipv4_skb_to_auditdata(skb, &ad.a, NULL); | ||
2739 | #endif | ||
2540 | /* | 2740 | /* |
2541 | * Receiving a packet requires that the other end be able to write | 2741 | * Receiving a packet requires that the other end be able to write |
2542 | * here. Read access is not required. | 2742 | * here. Read access is not required. |
2543 | */ | 2743 | */ |
2544 | rc = smk_access(smack, ssp->smk_in, MAY_WRITE); | 2744 | rc = smk_access(smack, ssp->smk_in, MAY_WRITE, &ad); |
2545 | if (rc != 0) | 2745 | if (rc != 0) |
2546 | return rc; | 2746 | return rc; |
2547 | 2747 | ||
@@ -2643,6 +2843,7 @@ static int smack_key_permission(key_ref_t key_ref, | |||
2643 | const struct cred *cred, key_perm_t perm) | 2843 | const struct cred *cred, key_perm_t perm) |
2644 | { | 2844 | { |
2645 | struct key *keyp; | 2845 | struct key *keyp; |
2846 | struct smk_audit_info ad; | ||
2646 | 2847 | ||
2647 | keyp = key_ref_to_ptr(key_ref); | 2848 | keyp = key_ref_to_ptr(key_ref); |
2648 | if (keyp == NULL) | 2849 | if (keyp == NULL) |
@@ -2658,8 +2859,13 @@ static int smack_key_permission(key_ref_t key_ref, | |||
2658 | */ | 2859 | */ |
2659 | if (cred->security == NULL) | 2860 | if (cred->security == NULL) |
2660 | return -EACCES; | 2861 | return -EACCES; |
2661 | 2862 | #ifdef CONFIG_AUDIT | |
2662 | return smk_access(cred->security, keyp->security, MAY_READWRITE); | 2863 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY); |
2864 | ad.a.u.key_struct.key = keyp->serial; | ||
2865 | ad.a.u.key_struct.key_desc = keyp->description; | ||
2866 | #endif | ||
2867 | return smk_access(cred->security, keyp->security, | ||
2868 | MAY_READWRITE, &ad); | ||
2663 | } | 2869 | } |
2664 | #endif /* CONFIG_KEYS */ | 2870 | #endif /* CONFIG_KEYS */ |
2665 | 2871 | ||
@@ -2828,15 +3034,7 @@ struct security_operations smack_ops = { | |||
2828 | 3034 | ||
2829 | .ptrace_may_access = smack_ptrace_may_access, | 3035 | .ptrace_may_access = smack_ptrace_may_access, |
2830 | .ptrace_traceme = smack_ptrace_traceme, | 3036 | .ptrace_traceme = smack_ptrace_traceme, |
2831 | .capget = cap_capget, | ||
2832 | .capset = cap_capset, | ||
2833 | .capable = cap_capable, | ||
2834 | .syslog = smack_syslog, | 3037 | .syslog = smack_syslog, |
2835 | .settime = cap_settime, | ||
2836 | .vm_enough_memory = cap_vm_enough_memory, | ||
2837 | |||
2838 | .bprm_set_creds = cap_bprm_set_creds, | ||
2839 | .bprm_secureexec = cap_bprm_secureexec, | ||
2840 | 3038 | ||
2841 | .sb_alloc_security = smack_sb_alloc_security, | 3039 | .sb_alloc_security = smack_sb_alloc_security, |
2842 | .sb_free_security = smack_sb_free_security, | 3040 | .sb_free_security = smack_sb_free_security, |
@@ -2860,8 +3058,6 @@ struct security_operations smack_ops = { | |||
2860 | .inode_post_setxattr = smack_inode_post_setxattr, | 3058 | .inode_post_setxattr = smack_inode_post_setxattr, |
2861 | .inode_getxattr = smack_inode_getxattr, | 3059 | .inode_getxattr = smack_inode_getxattr, |
2862 | .inode_removexattr = smack_inode_removexattr, | 3060 | .inode_removexattr = smack_inode_removexattr, |
2863 | .inode_need_killpriv = cap_inode_need_killpriv, | ||
2864 | .inode_killpriv = cap_inode_killpriv, | ||
2865 | .inode_getsecurity = smack_inode_getsecurity, | 3061 | .inode_getsecurity = smack_inode_getsecurity, |
2866 | .inode_setsecurity = smack_inode_setsecurity, | 3062 | .inode_setsecurity = smack_inode_setsecurity, |
2867 | .inode_listsecurity = smack_inode_listsecurity, | 3063 | .inode_listsecurity = smack_inode_listsecurity, |
@@ -2882,7 +3078,6 @@ struct security_operations smack_ops = { | |||
2882 | .cred_commit = smack_cred_commit, | 3078 | .cred_commit = smack_cred_commit, |
2883 | .kernel_act_as = smack_kernel_act_as, | 3079 | .kernel_act_as = smack_kernel_act_as, |
2884 | .kernel_create_files_as = smack_kernel_create_files_as, | 3080 | .kernel_create_files_as = smack_kernel_create_files_as, |
2885 | .task_fix_setuid = cap_task_fix_setuid, | ||
2886 | .task_setpgid = smack_task_setpgid, | 3081 | .task_setpgid = smack_task_setpgid, |
2887 | .task_getpgid = smack_task_getpgid, | 3082 | .task_getpgid = smack_task_getpgid, |
2888 | .task_getsid = smack_task_getsid, | 3083 | .task_getsid = smack_task_getsid, |
@@ -2896,7 +3091,6 @@ struct security_operations smack_ops = { | |||
2896 | .task_kill = smack_task_kill, | 3091 | .task_kill = smack_task_kill, |
2897 | .task_wait = smack_task_wait, | 3092 | .task_wait = smack_task_wait, |
2898 | .task_to_inode = smack_task_to_inode, | 3093 | .task_to_inode = smack_task_to_inode, |
2899 | .task_prctl = cap_task_prctl, | ||
2900 | 3094 | ||
2901 | .ipc_permission = smack_ipc_permission, | 3095 | .ipc_permission = smack_ipc_permission, |
2902 | .ipc_getsecid = smack_ipc_getsecid, | 3096 | .ipc_getsecid = smack_ipc_getsecid, |
@@ -2923,9 +3117,6 @@ struct security_operations smack_ops = { | |||
2923 | .sem_semctl = smack_sem_semctl, | 3117 | .sem_semctl = smack_sem_semctl, |
2924 | .sem_semop = smack_sem_semop, | 3118 | .sem_semop = smack_sem_semop, |
2925 | 3119 | ||
2926 | .netlink_send = cap_netlink_send, | ||
2927 | .netlink_recv = cap_netlink_recv, | ||
2928 | |||
2929 | .d_instantiate = smack_d_instantiate, | 3120 | .d_instantiate = smack_d_instantiate, |
2930 | 3121 | ||
2931 | .getprocattr = smack_getprocattr, | 3122 | .getprocattr = smack_getprocattr, |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index e03a7e19c73b..8d3c2a051c7b 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -41,6 +41,7 @@ enum smk_inos { | |||
41 | SMK_AMBIENT = 7, /* internet ambient label */ | 41 | SMK_AMBIENT = 7, /* internet ambient label */ |
42 | SMK_NETLBLADDR = 8, /* single label hosts */ | 42 | SMK_NETLBLADDR = 8, /* single label hosts */ |
43 | SMK_ONLYCAP = 9, /* the only "capable" label */ | 43 | SMK_ONLYCAP = 9, /* the only "capable" label */ |
44 | SMK_LOGGING = 10, /* logging */ | ||
44 | }; | 45 | }; |
45 | 46 | ||
46 | /* | 47 | /* |
@@ -775,7 +776,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
775 | struct sockaddr_in newname; | 776 | struct sockaddr_in newname; |
776 | char smack[SMK_LABELLEN]; | 777 | char smack[SMK_LABELLEN]; |
777 | char *sp; | 778 | char *sp; |
778 | char data[SMK_NETLBLADDRMAX]; | 779 | char data[SMK_NETLBLADDRMAX + 1]; |
779 | char *host = (char *)&newname.sin_addr.s_addr; | 780 | char *host = (char *)&newname.sin_addr.s_addr; |
780 | int rc; | 781 | int rc; |
781 | struct netlbl_audit audit_info; | 782 | struct netlbl_audit audit_info; |
@@ -1192,6 +1193,69 @@ static const struct file_operations smk_onlycap_ops = { | |||
1192 | }; | 1193 | }; |
1193 | 1194 | ||
1194 | /** | 1195 | /** |
1196 | * smk_read_logging - read() for /smack/logging | ||
1197 | * @filp: file pointer, not actually used | ||
1198 | * @buf: where to put the result | ||
1199 | * @cn: maximum to send along | ||
1200 | * @ppos: where to start | ||
1201 | * | ||
1202 | * Returns number of bytes read or error code, as appropriate | ||
1203 | */ | ||
1204 | static ssize_t smk_read_logging(struct file *filp, char __user *buf, | ||
1205 | size_t count, loff_t *ppos) | ||
1206 | { | ||
1207 | char temp[32]; | ||
1208 | ssize_t rc; | ||
1209 | |||
1210 | if (*ppos != 0) | ||
1211 | return 0; | ||
1212 | |||
1213 | sprintf(temp, "%d\n", log_policy); | ||
1214 | rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); | ||
1215 | return rc; | ||
1216 | } | ||
1217 | |||
1218 | /** | ||
1219 | * smk_write_logging - write() for /smack/logging | ||
1220 | * @file: file pointer, not actually used | ||
1221 | * @buf: where to get the data from | ||
1222 | * @count: bytes sent | ||
1223 | * @ppos: where to start | ||
1224 | * | ||
1225 | * Returns number of bytes written or error code, as appropriate | ||
1226 | */ | ||
1227 | static ssize_t smk_write_logging(struct file *file, const char __user *buf, | ||
1228 | size_t count, loff_t *ppos) | ||
1229 | { | ||
1230 | char temp[32]; | ||
1231 | int i; | ||
1232 | |||
1233 | if (!capable(CAP_MAC_ADMIN)) | ||
1234 | return -EPERM; | ||
1235 | |||
1236 | if (count >= sizeof(temp) || count == 0) | ||
1237 | return -EINVAL; | ||
1238 | |||
1239 | if (copy_from_user(temp, buf, count) != 0) | ||
1240 | return -EFAULT; | ||
1241 | |||
1242 | temp[count] = '\0'; | ||
1243 | |||
1244 | if (sscanf(temp, "%d", &i) != 1) | ||
1245 | return -EINVAL; | ||
1246 | if (i < 0 || i > 3) | ||
1247 | return -EINVAL; | ||
1248 | log_policy = i; | ||
1249 | return count; | ||
1250 | } | ||
1251 | |||
1252 | |||
1253 | |||
1254 | static const struct file_operations smk_logging_ops = { | ||
1255 | .read = smk_read_logging, | ||
1256 | .write = smk_write_logging, | ||
1257 | }; | ||
1258 | /** | ||
1195 | * smk_fill_super - fill the /smackfs superblock | 1259 | * smk_fill_super - fill the /smackfs superblock |
1196 | * @sb: the empty superblock | 1260 | * @sb: the empty superblock |
1197 | * @data: unused | 1261 | * @data: unused |
@@ -1221,6 +1285,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
1221 | {"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR}, | 1285 | {"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR}, |
1222 | [SMK_ONLYCAP] = | 1286 | [SMK_ONLYCAP] = |
1223 | {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, | 1287 | {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, |
1288 | [SMK_LOGGING] = | ||
1289 | {"logging", &smk_logging_ops, S_IRUGO|S_IWUSR}, | ||
1224 | /* last one */ {""} | 1290 | /* last one */ {""} |
1225 | }; | 1291 | }; |
1226 | 1292 | ||
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index ddfb9cccf468..fdd1f4b8c448 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -28,7 +28,13 @@ static const char *tomoyo_mode_2[4] = { | |||
28 | "disabled", "enabled", "enabled", "enabled" | 28 | "disabled", "enabled", "enabled", "enabled" |
29 | }; | 29 | }; |
30 | 30 | ||
31 | /* Table for profile. */ | 31 | /* |
32 | * tomoyo_control_array is a static data which contains | ||
33 | * | ||
34 | * (1) functionality name used by /sys/kernel/security/tomoyo/profile . | ||
35 | * (2) initial values for "struct tomoyo_profile". | ||
36 | * (3) max values for "struct tomoyo_profile". | ||
37 | */ | ||
32 | static struct { | 38 | static struct { |
33 | const char *keyword; | 39 | const char *keyword; |
34 | unsigned int current_value; | 40 | unsigned int current_value; |
@@ -39,7 +45,13 @@ static struct { | |||
39 | [TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 }, | 45 | [TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 }, |
40 | }; | 46 | }; |
41 | 47 | ||
42 | /* Profile table. Memory is allocated as needed. */ | 48 | /* |
49 | * tomoyo_profile is a structure which is used for holding the mode of access | ||
50 | * controls. TOMOYO has 4 modes: disabled, learning, permissive, enforcing. | ||
51 | * An administrator can define up to 256 profiles. | ||
52 | * The ->profile of "struct tomoyo_domain_info" is used for remembering | ||
53 | * the profile's number (0 - 255) assigned to that domain. | ||
54 | */ | ||
43 | static struct tomoyo_profile { | 55 | static struct tomoyo_profile { |
44 | unsigned int value[TOMOYO_MAX_CONTROL_INDEX]; | 56 | unsigned int value[TOMOYO_MAX_CONTROL_INDEX]; |
45 | const struct tomoyo_path_info *comment; | 57 | const struct tomoyo_path_info *comment; |
@@ -428,7 +440,6 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) | |||
428 | const char *name = ptr->name; | 440 | const char *name = ptr->name; |
429 | const int len = strlen(name); | 441 | const int len = strlen(name); |
430 | 442 | ||
431 | ptr->total_len = len; | ||
432 | ptr->const_len = tomoyo_const_part_length(name); | 443 | ptr->const_len = tomoyo_const_part_length(name); |
433 | ptr->is_dir = len && (name[len - 1] == '/'); | 444 | ptr->is_dir = len && (name[len - 1] == '/'); |
434 | ptr->is_patterned = (ptr->const_len < len); | 445 | ptr->is_patterned = (ptr->const_len < len); |
@@ -866,7 +877,6 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned | |||
866 | 877 | ||
867 | if (profile >= TOMOYO_MAX_PROFILES) | 878 | if (profile >= TOMOYO_MAX_PROFILES) |
868 | return NULL; | 879 | return NULL; |
869 | /***** EXCLUSIVE SECTION START *****/ | ||
870 | mutex_lock(&lock); | 880 | mutex_lock(&lock); |
871 | ptr = tomoyo_profile_ptr[profile]; | 881 | ptr = tomoyo_profile_ptr[profile]; |
872 | if (ptr) | 882 | if (ptr) |
@@ -880,7 +890,6 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned | |||
880 | tomoyo_profile_ptr[profile] = ptr; | 890 | tomoyo_profile_ptr[profile] = ptr; |
881 | ok: | 891 | ok: |
882 | mutex_unlock(&lock); | 892 | mutex_unlock(&lock); |
883 | /***** EXCLUSIVE SECTION END *****/ | ||
884 | return ptr; | 893 | return ptr; |
885 | } | 894 | } |
886 | 895 | ||
@@ -1009,7 +1018,19 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
1009 | return 0; | 1018 | return 0; |
1010 | } | 1019 | } |
1011 | 1020 | ||
1012 | /* Structure for policy manager. */ | 1021 | /* |
1022 | * tomoyo_policy_manager_entry is a structure which is used for holding list of | ||
1023 | * domainnames or programs which are permitted to modify configuration via | ||
1024 | * /sys/kernel/security/tomoyo/ interface. | ||
1025 | * It has following fields. | ||
1026 | * | ||
1027 | * (1) "list" which is linked to tomoyo_policy_manager_list . | ||
1028 | * (2) "manager" is a domainname or a program's pathname. | ||
1029 | * (3) "is_domain" is a bool which is true if "manager" is a domainname, false | ||
1030 | * otherwise. | ||
1031 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
1032 | * otherwise. | ||
1033 | */ | ||
1013 | struct tomoyo_policy_manager_entry { | 1034 | struct tomoyo_policy_manager_entry { |
1014 | struct list_head list; | 1035 | struct list_head list; |
1015 | /* A path to program or a domainname. */ | 1036 | /* A path to program or a domainname. */ |
@@ -1018,7 +1039,36 @@ struct tomoyo_policy_manager_entry { | |||
1018 | bool is_deleted; /* True if this entry is deleted. */ | 1039 | bool is_deleted; /* True if this entry is deleted. */ |
1019 | }; | 1040 | }; |
1020 | 1041 | ||
1021 | /* The list for "struct tomoyo_policy_manager_entry". */ | 1042 | /* |
1043 | * tomoyo_policy_manager_list is used for holding list of domainnames or | ||
1044 | * programs which are permitted to modify configuration via | ||
1045 | * /sys/kernel/security/tomoyo/ interface. | ||
1046 | * | ||
1047 | * An entry is added by | ||
1048 | * | ||
1049 | * # echo '<kernel> /sbin/mingetty /bin/login /bin/bash' > \ | ||
1050 | * /sys/kernel/security/tomoyo/manager | ||
1051 | * (if you want to specify by a domainname) | ||
1052 | * | ||
1053 | * or | ||
1054 | * | ||
1055 | * # echo '/usr/lib/ccs/editpolicy' > /sys/kernel/security/tomoyo/manager | ||
1056 | * (if you want to specify by a program's location) | ||
1057 | * | ||
1058 | * and is deleted by | ||
1059 | * | ||
1060 | * # echo 'delete <kernel> /sbin/mingetty /bin/login /bin/bash' > \ | ||
1061 | * /sys/kernel/security/tomoyo/manager | ||
1062 | * | ||
1063 | * or | ||
1064 | * | ||
1065 | * # echo 'delete /usr/lib/ccs/editpolicy' > \ | ||
1066 | * /sys/kernel/security/tomoyo/manager | ||
1067 | * | ||
1068 | * and all entries are retrieved by | ||
1069 | * | ||
1070 | * # cat /sys/kernel/security/tomoyo/manager | ||
1071 | */ | ||
1022 | static LIST_HEAD(tomoyo_policy_manager_list); | 1072 | static LIST_HEAD(tomoyo_policy_manager_list); |
1023 | static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); | 1073 | static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); |
1024 | 1074 | ||
@@ -1050,7 +1100,6 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
1050 | saved_manager = tomoyo_save_name(manager); | 1100 | saved_manager = tomoyo_save_name(manager); |
1051 | if (!saved_manager) | 1101 | if (!saved_manager) |
1052 | return -ENOMEM; | 1102 | return -ENOMEM; |
1053 | /***** EXCLUSIVE SECTION START *****/ | ||
1054 | down_write(&tomoyo_policy_manager_list_lock); | 1103 | down_write(&tomoyo_policy_manager_list_lock); |
1055 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { | 1104 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { |
1056 | if (ptr->manager != saved_manager) | 1105 | if (ptr->manager != saved_manager) |
@@ -1072,7 +1121,6 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
1072 | error = 0; | 1121 | error = 0; |
1073 | out: | 1122 | out: |
1074 | up_write(&tomoyo_policy_manager_list_lock); | 1123 | up_write(&tomoyo_policy_manager_list_lock); |
1075 | /***** EXCLUSIVE SECTION END *****/ | ||
1076 | return error; | 1124 | return error; |
1077 | } | 1125 | } |
1078 | 1126 | ||
@@ -1117,10 +1165,9 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) | |||
1117 | list); | 1165 | list); |
1118 | if (ptr->is_deleted) | 1166 | if (ptr->is_deleted) |
1119 | continue; | 1167 | continue; |
1120 | if (!tomoyo_io_printf(head, "%s\n", ptr->manager->name)) { | 1168 | done = tomoyo_io_printf(head, "%s\n", ptr->manager->name); |
1121 | done = false; | 1169 | if (!done) |
1122 | break; | 1170 | break; |
1123 | } | ||
1124 | } | 1171 | } |
1125 | up_read(&tomoyo_policy_manager_list_lock); | 1172 | up_read(&tomoyo_policy_manager_list_lock); |
1126 | head->read_eof = done; | 1173 | head->read_eof = done; |
@@ -1197,13 +1244,11 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | |||
1197 | 1244 | ||
1198 | if (sscanf(data, "pid=%u", &pid) == 1) { | 1245 | if (sscanf(data, "pid=%u", &pid) == 1) { |
1199 | struct task_struct *p; | 1246 | struct task_struct *p; |
1200 | /***** CRITICAL SECTION START *****/ | ||
1201 | read_lock(&tasklist_lock); | 1247 | read_lock(&tasklist_lock); |
1202 | p = find_task_by_vpid(pid); | 1248 | p = find_task_by_vpid(pid); |
1203 | if (p) | 1249 | if (p) |
1204 | domain = tomoyo_real_domain(p); | 1250 | domain = tomoyo_real_domain(p); |
1205 | read_unlock(&tasklist_lock); | 1251 | read_unlock(&tasklist_lock); |
1206 | /***** CRITICAL SECTION END *****/ | ||
1207 | } else if (!strncmp(data, "domain=", 7)) { | 1252 | } else if (!strncmp(data, "domain=", 7)) { |
1208 | if (tomoyo_is_domain_def(data + 7)) { | 1253 | if (tomoyo_is_domain_def(data + 7)) { |
1209 | down_read(&tomoyo_domain_list_lock); | 1254 | down_read(&tomoyo_domain_list_lock); |
@@ -1447,15 +1492,14 @@ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) | |||
1447 | TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) | 1492 | TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) |
1448 | ignore_global_allow_read | 1493 | ignore_global_allow_read |
1449 | = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; | 1494 | = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; |
1450 | if (!tomoyo_io_printf(head, | 1495 | done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE |
1451 | "%s\n" TOMOYO_KEYWORD_USE_PROFILE "%u\n" | 1496 | "%u\n%s%s%s\n", |
1452 | "%s%s%s\n", domain->domainname->name, | 1497 | domain->domainname->name, |
1453 | domain->profile, quota_exceeded, | 1498 | domain->profile, quota_exceeded, |
1454 | transition_failed, | 1499 | transition_failed, |
1455 | ignore_global_allow_read)) { | 1500 | ignore_global_allow_read); |
1456 | done = false; | 1501 | if (!done) |
1457 | break; | 1502 | break; |
1458 | } | ||
1459 | head->read_step = 2; | 1503 | head->read_step = 2; |
1460 | acl_loop: | 1504 | acl_loop: |
1461 | if (head->read_step == 3) | 1505 | if (head->read_step == 3) |
@@ -1463,24 +1507,22 @@ acl_loop: | |||
1463 | /* Print ACL entries in the domain. */ | 1507 | /* Print ACL entries in the domain. */ |
1464 | down_read(&tomoyo_domain_acl_info_list_lock); | 1508 | down_read(&tomoyo_domain_acl_info_list_lock); |
1465 | list_for_each_cookie(apos, head->read_var2, | 1509 | list_for_each_cookie(apos, head->read_var2, |
1466 | &domain->acl_info_list) { | 1510 | &domain->acl_info_list) { |
1467 | struct tomoyo_acl_info *ptr | 1511 | struct tomoyo_acl_info *ptr |
1468 | = list_entry(apos, struct tomoyo_acl_info, | 1512 | = list_entry(apos, struct tomoyo_acl_info, |
1469 | list); | 1513 | list); |
1470 | if (!tomoyo_print_entry(head, ptr)) { | 1514 | done = tomoyo_print_entry(head, ptr); |
1471 | done = false; | 1515 | if (!done) |
1472 | break; | 1516 | break; |
1473 | } | ||
1474 | } | 1517 | } |
1475 | up_read(&tomoyo_domain_acl_info_list_lock); | 1518 | up_read(&tomoyo_domain_acl_info_list_lock); |
1476 | if (!done) | 1519 | if (!done) |
1477 | break; | 1520 | break; |
1478 | head->read_step = 3; | 1521 | head->read_step = 3; |
1479 | tail_mark: | 1522 | tail_mark: |
1480 | if (!tomoyo_io_printf(head, "\n")) { | 1523 | done = tomoyo_io_printf(head, "\n"); |
1481 | done = false; | 1524 | if (!done) |
1482 | break; | 1525 | break; |
1483 | } | ||
1484 | head->read_step = 1; | 1526 | head->read_step = 1; |
1485 | if (head->read_single_domain) | 1527 | if (head->read_single_domain) |
1486 | break; | 1528 | break; |
@@ -1550,11 +1592,10 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) | |||
1550 | domain = list_entry(pos, struct tomoyo_domain_info, list); | 1592 | domain = list_entry(pos, struct tomoyo_domain_info, list); |
1551 | if (domain->is_deleted) | 1593 | if (domain->is_deleted) |
1552 | continue; | 1594 | continue; |
1553 | if (!tomoyo_io_printf(head, "%u %s\n", domain->profile, | 1595 | done = tomoyo_io_printf(head, "%u %s\n", domain->profile, |
1554 | domain->domainname->name)) { | 1596 | domain->domainname->name); |
1555 | done = false; | 1597 | if (!done) |
1556 | break; | 1598 | break; |
1557 | } | ||
1558 | } | 1599 | } |
1559 | up_read(&tomoyo_domain_list_lock); | 1600 | up_read(&tomoyo_domain_list_lock); |
1560 | head->read_eof = done; | 1601 | head->read_eof = done; |
@@ -1594,13 +1635,11 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head) | |||
1594 | const int pid = head->read_step; | 1635 | const int pid = head->read_step; |
1595 | struct task_struct *p; | 1636 | struct task_struct *p; |
1596 | struct tomoyo_domain_info *domain = NULL; | 1637 | struct tomoyo_domain_info *domain = NULL; |
1597 | /***** CRITICAL SECTION START *****/ | ||
1598 | read_lock(&tasklist_lock); | 1638 | read_lock(&tasklist_lock); |
1599 | p = find_task_by_vpid(pid); | 1639 | p = find_task_by_vpid(pid); |
1600 | if (p) | 1640 | if (p) |
1601 | domain = tomoyo_real_domain(p); | 1641 | domain = tomoyo_real_domain(p); |
1602 | read_unlock(&tasklist_lock); | 1642 | read_unlock(&tasklist_lock); |
1603 | /***** CRITICAL SECTION END *****/ | ||
1604 | if (domain) | 1643 | if (domain) |
1605 | tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, | 1644 | tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, |
1606 | domain->domainname->name); | 1645 | domain->domainname->name); |
@@ -2138,7 +2177,13 @@ static ssize_t tomoyo_write(struct file *file, const char __user *buf, | |||
2138 | return tomoyo_write_control(file, buf, count); | 2177 | return tomoyo_write_control(file, buf, count); |
2139 | } | 2178 | } |
2140 | 2179 | ||
2141 | /* Operations for /sys/kernel/security/tomoyo/ interface. */ | 2180 | /* |
2181 | * tomoyo_operations is a "struct file_operations" which is used for handling | ||
2182 | * /sys/kernel/security/tomoyo/ interface. | ||
2183 | * | ||
2184 | * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). | ||
2185 | * See tomoyo_io_buffer for internals. | ||
2186 | */ | ||
2142 | static const struct file_operations tomoyo_operations = { | 2187 | static const struct file_operations tomoyo_operations = { |
2143 | .open = tomoyo_open, | 2188 | .open = tomoyo_open, |
2144 | .release = tomoyo_release, | 2189 | .release = tomoyo_release, |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 678f4ff16aa4..6d6ba09af457 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -26,16 +26,43 @@ | |||
26 | struct dentry; | 26 | struct dentry; |
27 | struct vfsmount; | 27 | struct vfsmount; |
28 | 28 | ||
29 | /* Temporary buffer for holding pathnames. */ | 29 | /* |
30 | * tomoyo_page_buffer is a structure which is used for holding a pathname | ||
31 | * obtained from "struct dentry" and "struct vfsmount" pair. | ||
32 | * As of now, it is 4096 bytes. If users complain that 4096 bytes is too small | ||
33 | * (because TOMOYO escapes non ASCII printable characters using \ooo format), | ||
34 | * we will make the buffer larger. | ||
35 | */ | ||
30 | struct tomoyo_page_buffer { | 36 | struct tomoyo_page_buffer { |
31 | char buffer[4096]; | 37 | char buffer[4096]; |
32 | }; | 38 | }; |
33 | 39 | ||
34 | /* Structure for holding a token. */ | 40 | /* |
41 | * tomoyo_path_info is a structure which is used for holding a string data | ||
42 | * used by TOMOYO. | ||
43 | * This structure has several fields for supporting pattern matching. | ||
44 | * | ||
45 | * (1) "name" is the '\0' terminated string data. | ||
46 | * (2) "hash" is full_name_hash(name, strlen(name)). | ||
47 | * This allows tomoyo_pathcmp() to compare by hash before actually compare | ||
48 | * using strcmp(). | ||
49 | * (3) "const_len" is the length of the initial segment of "name" which | ||
50 | * consists entirely of non wildcard characters. In other words, the length | ||
51 | * which we can compare two strings using strncmp(). | ||
52 | * (4) "is_dir" is a bool which is true if "name" ends with "/", | ||
53 | * false otherwise. | ||
54 | * TOMOYO distinguishes directory and non-directory. A directory ends with | ||
55 | * "/" and non-directory does not end with "/". | ||
56 | * (5) "is_patterned" is a bool which is true if "name" contains wildcard | ||
57 | * characters, false otherwise. This allows TOMOYO to use "hash" and | ||
58 | * strcmp() for string comparison if "is_patterned" is false. | ||
59 | * (6) "depth" is calculated using the number of "/" characters in "name". | ||
60 | * This allows TOMOYO to avoid comparing two pathnames which never match | ||
61 | * (e.g. whether "/var/www/html/index.html" matches "/tmp/sh-thd-\$"). | ||
62 | */ | ||
35 | struct tomoyo_path_info { | 63 | struct tomoyo_path_info { |
36 | const char *name; | 64 | const char *name; |
37 | u32 hash; /* = full_name_hash(name, strlen(name)) */ | 65 | u32 hash; /* = full_name_hash(name, strlen(name)) */ |
38 | u16 total_len; /* = strlen(name) */ | ||
39 | u16 const_len; /* = tomoyo_const_part_length(name) */ | 66 | u16 const_len; /* = tomoyo_const_part_length(name) */ |
40 | bool is_dir; /* = tomoyo_strendswith(name, "/") */ | 67 | bool is_dir; /* = tomoyo_strendswith(name, "/") */ |
41 | bool is_patterned; /* = tomoyo_path_contains_pattern(name) */ | 68 | bool is_patterned; /* = tomoyo_path_contains_pattern(name) */ |
@@ -51,7 +78,20 @@ struct tomoyo_path_info { | |||
51 | */ | 78 | */ |
52 | #define TOMOYO_MAX_PATHNAME_LEN 4000 | 79 | #define TOMOYO_MAX_PATHNAME_LEN 4000 |
53 | 80 | ||
54 | /* Structure for holding requested pathname. */ | 81 | /* |
82 | * tomoyo_path_info_with_data is a structure which is used for holding a | ||
83 | * pathname obtained from "struct dentry" and "struct vfsmount" pair. | ||
84 | * | ||
85 | * "struct tomoyo_path_info_with_data" consists of "struct tomoyo_path_info" | ||
86 | * and buffer for the pathname, while "struct tomoyo_page_buffer" consists of | ||
87 | * buffer for the pathname only. | ||
88 | * | ||
89 | * "struct tomoyo_path_info_with_data" is intended to allow TOMOYO to release | ||
90 | * both "struct tomoyo_path_info" and buffer for the pathname by single kfree() | ||
91 | * so that we don't need to return two pointers to the caller. If the caller | ||
92 | * puts "struct tomoyo_path_info" on stack memory, we will be able to remove | ||
93 | * "struct tomoyo_path_info_with_data". | ||
94 | */ | ||
55 | struct tomoyo_path_info_with_data { | 95 | struct tomoyo_path_info_with_data { |
56 | /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ | 96 | /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ |
57 | struct tomoyo_path_info head; | 97 | struct tomoyo_path_info head; |
@@ -61,7 +101,15 @@ struct tomoyo_path_info_with_data { | |||
61 | }; | 101 | }; |
62 | 102 | ||
63 | /* | 103 | /* |
64 | * Common header for holding ACL entries. | 104 | * tomoyo_acl_info is a structure which is used for holding |
105 | * | ||
106 | * (1) "list" which is linked to the ->acl_info_list of | ||
107 | * "struct tomoyo_domain_info" | ||
108 | * (2) "type" which tells | ||
109 | * (a) type & 0x7F : type of the entry (either | ||
110 | * "struct tomoyo_single_path_acl_record" or | ||
111 | * "struct tomoyo_double_path_acl_record") | ||
112 | * (b) type & 0x80 : whether the entry is marked as "deleted". | ||
65 | * | 113 | * |
66 | * Packing "struct tomoyo_acl_info" allows | 114 | * Packing "struct tomoyo_acl_info" allows |
67 | * "struct tomoyo_single_path_acl_record" to embed "u16" and | 115 | * "struct tomoyo_single_path_acl_record" to embed "u16" and |
@@ -81,7 +129,28 @@ struct tomoyo_acl_info { | |||
81 | /* This ACL entry is deleted. */ | 129 | /* This ACL entry is deleted. */ |
82 | #define TOMOYO_ACL_DELETED 0x80 | 130 | #define TOMOYO_ACL_DELETED 0x80 |
83 | 131 | ||
84 | /* Structure for domain information. */ | 132 | /* |
133 | * tomoyo_domain_info is a structure which is used for holding permissions | ||
134 | * (e.g. "allow_read /lib/libc-2.5.so") given to each domain. | ||
135 | * It has following fields. | ||
136 | * | ||
137 | * (1) "list" which is linked to tomoyo_domain_list . | ||
138 | * (2) "acl_info_list" which is linked to "struct tomoyo_acl_info". | ||
139 | * (3) "domainname" which holds the name of the domain. | ||
140 | * (4) "profile" which remembers profile number assigned to this domain. | ||
141 | * (5) "is_deleted" is a bool which is true if this domain is marked as | ||
142 | * "deleted", false otherwise. | ||
143 | * (6) "quota_warned" is a bool which is used for suppressing warning message | ||
144 | * when learning mode learned too much entries. | ||
145 | * (7) "flags" which remembers this domain's attributes. | ||
146 | * | ||
147 | * A domain's lifecycle is an analogy of files on / directory. | ||
148 | * Multiple domains with the same domainname cannot be created (as with | ||
149 | * creating files with the same filename fails with -EEXIST). | ||
150 | * If a process reached a domain, that process can reside in that domain after | ||
151 | * that domain is marked as "deleted" (as with a process can access an already | ||
152 | * open()ed file after that file was unlink()ed). | ||
153 | */ | ||
85 | struct tomoyo_domain_info { | 154 | struct tomoyo_domain_info { |
86 | struct list_head list; | 155 | struct list_head list; |
87 | struct list_head acl_info_list; | 156 | struct list_head acl_info_list; |
@@ -108,10 +177,18 @@ struct tomoyo_domain_info { | |||
108 | #define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2 | 177 | #define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2 |
109 | 178 | ||
110 | /* | 179 | /* |
111 | * Structure for "allow_read/write", "allow_execute", "allow_read", | 180 | * tomoyo_single_path_acl_record is a structure which is used for holding an |
112 | * "allow_write", "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir", | 181 | * entry with one pathname operation (e.g. open(), mkdir()). |
113 | * "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar", | 182 | * It has following fields. |
114 | * "allow_truncate", "allow_symlink" and "allow_rewrite" directive. | 183 | * |
184 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
185 | * (2) "perm" which is a bitmask of permitted operations. | ||
186 | * (3) "filename" is the pathname. | ||
187 | * | ||
188 | * Directives held by this structure are "allow_read/write", "allow_execute", | ||
189 | * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", | ||
190 | * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock", | ||
191 | * "allow_mkchar", "allow_truncate", "allow_symlink" and "allow_rewrite". | ||
115 | */ | 192 | */ |
116 | struct tomoyo_single_path_acl_record { | 193 | struct tomoyo_single_path_acl_record { |
117 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */ | 194 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */ |
@@ -120,7 +197,18 @@ struct tomoyo_single_path_acl_record { | |||
120 | const struct tomoyo_path_info *filename; | 197 | const struct tomoyo_path_info *filename; |
121 | }; | 198 | }; |
122 | 199 | ||
123 | /* Structure for "allow_rename" and "allow_link" directive. */ | 200 | /* |
201 | * tomoyo_double_path_acl_record is a structure which is used for holding an | ||
202 | * entry with two pathnames operation (i.e. link() and rename()). | ||
203 | * It has following fields. | ||
204 | * | ||
205 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
206 | * (2) "perm" which is a bitmask of permitted operations. | ||
207 | * (3) "filename1" is the source/old pathname. | ||
208 | * (4) "filename2" is the destination/new pathname. | ||
209 | * | ||
210 | * Directives held by this structure are "allow_rename" and "allow_link". | ||
211 | */ | ||
124 | struct tomoyo_double_path_acl_record { | 212 | struct tomoyo_double_path_acl_record { |
125 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */ | 213 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */ |
126 | u8 perm; | 214 | u8 perm; |
@@ -153,7 +241,29 @@ struct tomoyo_double_path_acl_record { | |||
153 | #define TOMOYO_VERBOSE 2 | 241 | #define TOMOYO_VERBOSE 2 |
154 | #define TOMOYO_MAX_CONTROL_INDEX 3 | 242 | #define TOMOYO_MAX_CONTROL_INDEX 3 |
155 | 243 | ||
156 | /* Structure for reading/writing policy via securityfs interfaces. */ | 244 | /* |
245 | * tomoyo_io_buffer is a structure which is used for reading and modifying | ||
246 | * configuration via /sys/kernel/security/tomoyo/ interface. | ||
247 | * It has many fields. ->read_var1 , ->read_var2 , ->write_var1 are used as | ||
248 | * cursors. | ||
249 | * | ||
250 | * Since the content of /sys/kernel/security/tomoyo/domain_policy is a list of | ||
251 | * "struct tomoyo_domain_info" entries and each "struct tomoyo_domain_info" | ||
252 | * entry has a list of "struct tomoyo_acl_info", we need two cursors when | ||
253 | * reading (one is for traversing tomoyo_domain_list and the other is for | ||
254 | * traversing "struct tomoyo_acl_info"->acl_info_list ). | ||
255 | * | ||
256 | * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with | ||
257 | * "select ", TOMOYO seeks the cursor ->read_var1 and ->write_var1 to the | ||
258 | * domain with the domainname specified by the rest of that line (NULL is set | ||
259 | * if seek failed). | ||
260 | * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with | ||
261 | * "delete ", TOMOYO deletes an entry or a domain specified by the rest of that | ||
262 | * line (->write_var1 is set to NULL if a domain was deleted). | ||
263 | * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with | ||
264 | * neither "select " nor "delete ", an entry or a domain specified by that line | ||
265 | * is appended. | ||
266 | */ | ||
157 | struct tomoyo_io_buffer { | 267 | struct tomoyo_io_buffer { |
158 | int (*read) (struct tomoyo_io_buffer *); | 268 | int (*read) (struct tomoyo_io_buffer *); |
159 | int (*write) (struct tomoyo_io_buffer *); | 269 | int (*write) (struct tomoyo_io_buffer *); |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 2d6748741a26..1d8b16960576 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -19,11 +19,63 @@ | |||
19 | /* The initial domain. */ | 19 | /* The initial domain. */ |
20 | struct tomoyo_domain_info tomoyo_kernel_domain; | 20 | struct tomoyo_domain_info tomoyo_kernel_domain; |
21 | 21 | ||
22 | /* The list for "struct tomoyo_domain_info". */ | 22 | /* |
23 | * tomoyo_domain_list is used for holding list of domains. | ||
24 | * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding | ||
25 | * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain. | ||
26 | * | ||
27 | * An entry is added by | ||
28 | * | ||
29 | * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \ | ||
30 | * /sys/kernel/security/tomoyo/domain_policy | ||
31 | * | ||
32 | * and is deleted by | ||
33 | * | ||
34 | * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \ | ||
35 | * /sys/kernel/security/tomoyo/domain_policy | ||
36 | * | ||
37 | * and all entries are retrieved by | ||
38 | * | ||
39 | * # cat /sys/kernel/security/tomoyo/domain_policy | ||
40 | * | ||
41 | * A domain is added by | ||
42 | * | ||
43 | * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy | ||
44 | * | ||
45 | * and is deleted by | ||
46 | * | ||
47 | * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy | ||
48 | * | ||
49 | * and all domains are retrieved by | ||
50 | * | ||
51 | * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy | ||
52 | * | ||
53 | * Normally, a domainname is monotonically getting longer because a domainname | ||
54 | * which the process will belong to if an execve() operation succeeds is | ||
55 | * defined as a concatenation of "current domainname" + "pathname passed to | ||
56 | * execve()". | ||
57 | * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for | ||
58 | * exceptions. | ||
59 | */ | ||
23 | LIST_HEAD(tomoyo_domain_list); | 60 | LIST_HEAD(tomoyo_domain_list); |
24 | DECLARE_RWSEM(tomoyo_domain_list_lock); | 61 | DECLARE_RWSEM(tomoyo_domain_list_lock); |
25 | 62 | ||
26 | /* Structure for "initialize_domain" and "no_initialize_domain" keyword. */ | 63 | /* |
64 | * tomoyo_domain_initializer_entry is a structure which is used for holding | ||
65 | * "initialize_domain" and "no_initialize_domain" entries. | ||
66 | * It has following fields. | ||
67 | * | ||
68 | * (1) "list" which is linked to tomoyo_domain_initializer_list . | ||
69 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
70 | * domainname". This field is NULL if "from" clause is not specified. | ||
71 | * (3) "program" which is a program's pathname. | ||
72 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
73 | * otherwise. | ||
74 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
75 | * otherwise. | ||
76 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
77 | * component of a domainname", false otherwise. | ||
78 | */ | ||
27 | struct tomoyo_domain_initializer_entry { | 79 | struct tomoyo_domain_initializer_entry { |
28 | struct list_head list; | 80 | struct list_head list; |
29 | const struct tomoyo_path_info *domainname; /* This may be NULL */ | 81 | const struct tomoyo_path_info *domainname; /* This may be NULL */ |
@@ -34,7 +86,23 @@ struct tomoyo_domain_initializer_entry { | |||
34 | bool is_last_name; | 86 | bool is_last_name; |
35 | }; | 87 | }; |
36 | 88 | ||
37 | /* Structure for "keep_domain" and "no_keep_domain" keyword. */ | 89 | /* |
90 | * tomoyo_domain_keeper_entry is a structure which is used for holding | ||
91 | * "keep_domain" and "no_keep_domain" entries. | ||
92 | * It has following fields. | ||
93 | * | ||
94 | * (1) "list" which is linked to tomoyo_domain_keeper_list . | ||
95 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
96 | * domainname". | ||
97 | * (3) "program" which is a program's pathname. | ||
98 | * This field is NULL if "from" clause is not specified. | ||
99 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
100 | * otherwise. | ||
101 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
102 | * otherwise. | ||
103 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
104 | * component of a domainname", false otherwise. | ||
105 | */ | ||
38 | struct tomoyo_domain_keeper_entry { | 106 | struct tomoyo_domain_keeper_entry { |
39 | struct list_head list; | 107 | struct list_head list; |
40 | const struct tomoyo_path_info *domainname; | 108 | const struct tomoyo_path_info *domainname; |
@@ -45,7 +113,16 @@ struct tomoyo_domain_keeper_entry { | |||
45 | bool is_last_name; | 113 | bool is_last_name; |
46 | }; | 114 | }; |
47 | 115 | ||
48 | /* Structure for "alias" keyword. */ | 116 | /* |
117 | * tomoyo_alias_entry is a structure which is used for holding "alias" entries. | ||
118 | * It has following fields. | ||
119 | * | ||
120 | * (1) "list" which is linked to tomoyo_alias_list . | ||
121 | * (2) "original_name" which is a dereferenced pathname. | ||
122 | * (3) "aliased_name" which is a symlink's pathname. | ||
123 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
124 | * otherwise. | ||
125 | */ | ||
49 | struct tomoyo_alias_entry { | 126 | struct tomoyo_alias_entry { |
50 | struct list_head list; | 127 | struct list_head list; |
51 | const struct tomoyo_path_info *original_name; | 128 | const struct tomoyo_path_info *original_name; |
@@ -67,14 +144,12 @@ void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, | |||
67 | { | 144 | { |
68 | /* We need to serialize because this is bitfield operation. */ | 145 | /* We need to serialize because this is bitfield operation. */ |
69 | static DEFINE_SPINLOCK(lock); | 146 | static DEFINE_SPINLOCK(lock); |
70 | /***** CRITICAL SECTION START *****/ | ||
71 | spin_lock(&lock); | 147 | spin_lock(&lock); |
72 | if (!is_delete) | 148 | if (!is_delete) |
73 | domain->flags |= flags; | 149 | domain->flags |= flags; |
74 | else | 150 | else |
75 | domain->flags &= ~flags; | 151 | domain->flags &= ~flags; |
76 | spin_unlock(&lock); | 152 | spin_unlock(&lock); |
77 | /***** CRITICAL SECTION END *****/ | ||
78 | } | 153 | } |
79 | 154 | ||
80 | /** | 155 | /** |
@@ -94,7 +169,42 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) | |||
94 | return cp0; | 169 | return cp0; |
95 | } | 170 | } |
96 | 171 | ||
97 | /* The list for "struct tomoyo_domain_initializer_entry". */ | 172 | /* |
173 | * tomoyo_domain_initializer_list is used for holding list of programs which | ||
174 | * triggers reinitialization of domainname. Normally, a domainname is | ||
175 | * monotonically getting longer. But sometimes, we restart daemon programs. | ||
176 | * It would be convenient for us that "a daemon started upon system boot" and | ||
177 | * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO | ||
178 | * provides a way to shorten domainnames. | ||
179 | * | ||
180 | * An entry is added by | ||
181 | * | ||
182 | * # echo 'initialize_domain /usr/sbin/httpd' > \ | ||
183 | * /sys/kernel/security/tomoyo/exception_policy | ||
184 | * | ||
185 | * and is deleted by | ||
186 | * | ||
187 | * # echo 'delete initialize_domain /usr/sbin/httpd' > \ | ||
188 | * /sys/kernel/security/tomoyo/exception_policy | ||
189 | * | ||
190 | * and all entries are retrieved by | ||
191 | * | ||
192 | * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy | ||
193 | * | ||
194 | * In the example above, /usr/sbin/httpd will belong to | ||
195 | * "<kernel> /usr/sbin/httpd" domain. | ||
196 | * | ||
197 | * You may specify a domainname using "from" keyword. | ||
198 | * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd" | ||
199 | * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd" | ||
200 | * domain to belong to "<kernel> /usr/sbin/httpd" domain. | ||
201 | * | ||
202 | * You may add "no_" prefix to "initialize_domain". | ||
203 | * "initialize_domain /usr/sbin/httpd" and | ||
204 | * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd" | ||
205 | * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain | ||
206 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. | ||
207 | */ | ||
98 | static LIST_HEAD(tomoyo_domain_initializer_list); | 208 | static LIST_HEAD(tomoyo_domain_initializer_list); |
99 | static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); | 209 | static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); |
100 | 210 | ||
@@ -135,7 +245,6 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, | |||
135 | saved_program = tomoyo_save_name(program); | 245 | saved_program = tomoyo_save_name(program); |
136 | if (!saved_program) | 246 | if (!saved_program) |
137 | return -ENOMEM; | 247 | return -ENOMEM; |
138 | /***** EXCLUSIVE SECTION START *****/ | ||
139 | down_write(&tomoyo_domain_initializer_list_lock); | 248 | down_write(&tomoyo_domain_initializer_list_lock); |
140 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { | 249 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { |
141 | if (ptr->is_not != is_not || | 250 | if (ptr->is_not != is_not || |
@@ -161,7 +270,6 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, | |||
161 | error = 0; | 270 | error = 0; |
162 | out: | 271 | out: |
163 | up_write(&tomoyo_domain_initializer_list_lock); | 272 | up_write(&tomoyo_domain_initializer_list_lock); |
164 | /***** EXCLUSIVE SECTION END *****/ | ||
165 | return error; | 273 | return error; |
166 | } | 274 | } |
167 | 275 | ||
@@ -193,13 +301,12 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) | |||
193 | from = " from "; | 301 | from = " from "; |
194 | domain = ptr->domainname->name; | 302 | domain = ptr->domainname->name; |
195 | } | 303 | } |
196 | if (!tomoyo_io_printf(head, | 304 | done = tomoyo_io_printf(head, |
197 | "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN | 305 | "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN |
198 | "%s%s%s\n", no, ptr->program->name, from, | 306 | "%s%s%s\n", no, ptr->program->name, |
199 | domain)) { | 307 | from, domain); |
200 | done = false; | 308 | if (!done) |
201 | break; | 309 | break; |
202 | } | ||
203 | } | 310 | } |
204 | up_read(&tomoyo_domain_initializer_list_lock); | 311 | up_read(&tomoyo_domain_initializer_list_lock); |
205 | return done; | 312 | return done; |
@@ -273,7 +380,44 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
273 | return flag; | 380 | return flag; |
274 | } | 381 | } |
275 | 382 | ||
276 | /* The list for "struct tomoyo_domain_keeper_entry". */ | 383 | /* |
384 | * tomoyo_domain_keeper_list is used for holding list of domainnames which | ||
385 | * suppresses domain transition. Normally, a domainname is monotonically | ||
386 | * getting longer. But sometimes, we want to suppress domain transition. | ||
387 | * It would be convenient for us that programs executed from a login session | ||
388 | * belong to the same domain. Thus, TOMOYO provides a way to suppress domain | ||
389 | * transition. | ||
390 | * | ||
391 | * An entry is added by | ||
392 | * | ||
393 | * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \ | ||
394 | * /sys/kernel/security/tomoyo/exception_policy | ||
395 | * | ||
396 | * and is deleted by | ||
397 | * | ||
398 | * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \ | ||
399 | * /sys/kernel/security/tomoyo/exception_policy | ||
400 | * | ||
401 | * and all entries are retrieved by | ||
402 | * | ||
403 | * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy | ||
404 | * | ||
405 | * In the example above, any process which belongs to | ||
406 | * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain, | ||
407 | * unless explicitly specified by "initialize_domain" or "no_keep_domain". | ||
408 | * | ||
409 | * You may specify a program using "from" keyword. | ||
410 | * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash" | ||
411 | * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash" | ||
412 | * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain. | ||
413 | * | ||
414 | * You may add "no_" prefix to "keep_domain". | ||
415 | * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and | ||
416 | * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will | ||
417 | * cause "/usr/bin/passwd" to belong to | ||
418 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless | ||
419 | * explicitly specified by "initialize_domain". | ||
420 | */ | ||
277 | static LIST_HEAD(tomoyo_domain_keeper_list); | 421 | static LIST_HEAD(tomoyo_domain_keeper_list); |
278 | static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); | 422 | static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); |
279 | 423 | ||
@@ -296,7 +440,6 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, | |||
296 | struct tomoyo_domain_keeper_entry *ptr; | 440 | struct tomoyo_domain_keeper_entry *ptr; |
297 | const struct tomoyo_path_info *saved_domainname; | 441 | const struct tomoyo_path_info *saved_domainname; |
298 | const struct tomoyo_path_info *saved_program = NULL; | 442 | const struct tomoyo_path_info *saved_program = NULL; |
299 | static DEFINE_MUTEX(lock); | ||
300 | int error = -ENOMEM; | 443 | int error = -ENOMEM; |
301 | bool is_last_name = false; | 444 | bool is_last_name = false; |
302 | 445 | ||
@@ -315,7 +458,6 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, | |||
315 | saved_domainname = tomoyo_save_name(domainname); | 458 | saved_domainname = tomoyo_save_name(domainname); |
316 | if (!saved_domainname) | 459 | if (!saved_domainname) |
317 | return -ENOMEM; | 460 | return -ENOMEM; |
318 | /***** EXCLUSIVE SECTION START *****/ | ||
319 | down_write(&tomoyo_domain_keeper_list_lock); | 461 | down_write(&tomoyo_domain_keeper_list_lock); |
320 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { | 462 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { |
321 | if (ptr->is_not != is_not || | 463 | if (ptr->is_not != is_not || |
@@ -341,7 +483,6 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, | |||
341 | error = 0; | 483 | error = 0; |
342 | out: | 484 | out: |
343 | up_write(&tomoyo_domain_keeper_list_lock); | 485 | up_write(&tomoyo_domain_keeper_list_lock); |
344 | /***** EXCLUSIVE SECTION END *****/ | ||
345 | return error; | 486 | return error; |
346 | } | 487 | } |
347 | 488 | ||
@@ -394,13 +535,12 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) | |||
394 | from = " from "; | 535 | from = " from "; |
395 | program = ptr->program->name; | 536 | program = ptr->program->name; |
396 | } | 537 | } |
397 | if (!tomoyo_io_printf(head, | 538 | done = tomoyo_io_printf(head, |
398 | "%s" TOMOYO_KEYWORD_KEEP_DOMAIN | 539 | "%s" TOMOYO_KEYWORD_KEEP_DOMAIN |
399 | "%s%s%s\n", no, program, from, | 540 | "%s%s%s\n", no, program, from, |
400 | ptr->domainname->name)) { | 541 | ptr->domainname->name); |
401 | done = false; | 542 | if (!done) |
402 | break; | 543 | break; |
403 | } | ||
404 | } | 544 | } |
405 | up_read(&tomoyo_domain_keeper_list_lock); | 545 | up_read(&tomoyo_domain_keeper_list_lock); |
406 | return done; | 546 | return done; |
@@ -446,7 +586,36 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
446 | return flag; | 586 | return flag; |
447 | } | 587 | } |
448 | 588 | ||
449 | /* The list for "struct tomoyo_alias_entry". */ | 589 | /* |
590 | * tomoyo_alias_list is used for holding list of symlink's pathnames which are | ||
591 | * allowed to be passed to an execve() request. Normally, the domainname which | ||
592 | * the current process will belong to after execve() succeeds is calculated | ||
593 | * using dereferenced pathnames. But some programs behave differently depending | ||
594 | * on the name passed to argv[0]. For busybox, calculating domainname using | ||
595 | * dereferenced pathnames will cause all programs in the busybox to belong to | ||
596 | * the same domain. Thus, TOMOYO provides a way to allow use of symlink's | ||
597 | * pathname for checking execve()'s permission and calculating domainname which | ||
598 | * the current process will belong to after execve() succeeds. | ||
599 | * | ||
600 | * An entry is added by | ||
601 | * | ||
602 | * # echo 'alias /bin/busybox /bin/cat' > \ | ||
603 | * /sys/kernel/security/tomoyo/exception_policy | ||
604 | * | ||
605 | * and is deleted by | ||
606 | * | ||
607 | * # echo 'delete alias /bin/busybox /bin/cat' > \ | ||
608 | * /sys/kernel/security/tomoyo/exception_policy | ||
609 | * | ||
610 | * and all entries are retrieved by | ||
611 | * | ||
612 | * # grep ^alias /sys/kernel/security/tomoyo/exception_policy | ||
613 | * | ||
614 | * In the example above, if /bin/cat is a symlink to /bin/busybox and execution | ||
615 | * of /bin/cat is requested, permission is checked for /bin/cat rather than | ||
616 | * /bin/busybox and domainname which the current process will belong to after | ||
617 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . | ||
618 | */ | ||
450 | static LIST_HEAD(tomoyo_alias_list); | 619 | static LIST_HEAD(tomoyo_alias_list); |
451 | static DECLARE_RWSEM(tomoyo_alias_list_lock); | 620 | static DECLARE_RWSEM(tomoyo_alias_list_lock); |
452 | 621 | ||
@@ -476,7 +645,6 @@ static int tomoyo_update_alias_entry(const char *original_name, | |||
476 | saved_aliased_name = tomoyo_save_name(aliased_name); | 645 | saved_aliased_name = tomoyo_save_name(aliased_name); |
477 | if (!saved_original_name || !saved_aliased_name) | 646 | if (!saved_original_name || !saved_aliased_name) |
478 | return -ENOMEM; | 647 | return -ENOMEM; |
479 | /***** EXCLUSIVE SECTION START *****/ | ||
480 | down_write(&tomoyo_alias_list_lock); | 648 | down_write(&tomoyo_alias_list_lock); |
481 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { | 649 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { |
482 | if (ptr->original_name != saved_original_name || | 650 | if (ptr->original_name != saved_original_name || |
@@ -499,7 +667,6 @@ static int tomoyo_update_alias_entry(const char *original_name, | |||
499 | error = 0; | 667 | error = 0; |
500 | out: | 668 | out: |
501 | up_write(&tomoyo_alias_list_lock); | 669 | up_write(&tomoyo_alias_list_lock); |
502 | /***** EXCLUSIVE SECTION END *****/ | ||
503 | return error; | 670 | return error; |
504 | } | 671 | } |
505 | 672 | ||
@@ -522,12 +689,11 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) | |||
522 | ptr = list_entry(pos, struct tomoyo_alias_entry, list); | 689 | ptr = list_entry(pos, struct tomoyo_alias_entry, list); |
523 | if (ptr->is_deleted) | 690 | if (ptr->is_deleted) |
524 | continue; | 691 | continue; |
525 | if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n", | 692 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n", |
526 | ptr->original_name->name, | 693 | ptr->original_name->name, |
527 | ptr->aliased_name->name)) { | 694 | ptr->aliased_name->name); |
528 | done = false; | 695 | if (!done) |
529 | break; | 696 | break; |
530 | } | ||
531 | } | 697 | } |
532 | up_read(&tomoyo_alias_list_lock); | 698 | up_read(&tomoyo_alias_list_lock); |
533 | return done; | 699 | return done; |
@@ -567,7 +733,6 @@ int tomoyo_delete_domain(char *domainname) | |||
567 | 733 | ||
568 | name.name = domainname; | 734 | name.name = domainname; |
569 | tomoyo_fill_path_info(&name); | 735 | tomoyo_fill_path_info(&name); |
570 | /***** EXCLUSIVE SECTION START *****/ | ||
571 | down_write(&tomoyo_domain_list_lock); | 736 | down_write(&tomoyo_domain_list_lock); |
572 | /* Is there an active domain? */ | 737 | /* Is there an active domain? */ |
573 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | 738 | list_for_each_entry(domain, &tomoyo_domain_list, list) { |
@@ -581,7 +746,6 @@ int tomoyo_delete_domain(char *domainname) | |||
581 | break; | 746 | break; |
582 | } | 747 | } |
583 | up_write(&tomoyo_domain_list_lock); | 748 | up_write(&tomoyo_domain_list_lock); |
584 | /***** EXCLUSIVE SECTION END *****/ | ||
585 | return 0; | 749 | return 0; |
586 | } | 750 | } |
587 | 751 | ||
@@ -600,7 +764,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
600 | struct tomoyo_domain_info *domain = NULL; | 764 | struct tomoyo_domain_info *domain = NULL; |
601 | const struct tomoyo_path_info *saved_domainname; | 765 | const struct tomoyo_path_info *saved_domainname; |
602 | 766 | ||
603 | /***** EXCLUSIVE SECTION START *****/ | ||
604 | down_write(&tomoyo_domain_list_lock); | 767 | down_write(&tomoyo_domain_list_lock); |
605 | domain = tomoyo_find_domain(domainname); | 768 | domain = tomoyo_find_domain(domainname); |
606 | if (domain) | 769 | if (domain) |
@@ -619,7 +782,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
619 | domain->domainname != saved_domainname) | 782 | domain->domainname != saved_domainname) |
620 | continue; | 783 | continue; |
621 | flag = false; | 784 | flag = false; |
622 | /***** CRITICAL SECTION START *****/ | ||
623 | read_lock(&tasklist_lock); | 785 | read_lock(&tasklist_lock); |
624 | for_each_process(p) { | 786 | for_each_process(p) { |
625 | if (tomoyo_real_domain(p) != domain) | 787 | if (tomoyo_real_domain(p) != domain) |
@@ -628,7 +790,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
628 | break; | 790 | break; |
629 | } | 791 | } |
630 | read_unlock(&tasklist_lock); | 792 | read_unlock(&tasklist_lock); |
631 | /***** CRITICAL SECTION END *****/ | ||
632 | if (flag) | 793 | if (flag) |
633 | continue; | 794 | continue; |
634 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 795 | list_for_each_entry(ptr, &domain->acl_info_list, list) { |
@@ -651,7 +812,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
651 | } | 812 | } |
652 | out: | 813 | out: |
653 | up_write(&tomoyo_domain_list_lock); | 814 | up_write(&tomoyo_domain_list_lock); |
654 | /***** EXCLUSIVE SECTION END *****/ | ||
655 | return domain; | 815 | return domain; |
656 | } | 816 | } |
657 | 817 | ||
@@ -739,7 +899,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm, | |||
739 | } | 899 | } |
740 | 900 | ||
741 | /* Check execute permission. */ | 901 | /* Check execute permission. */ |
742 | retval = tomoyo_check_exec_perm(old_domain, &r, tmp); | 902 | retval = tomoyo_check_exec_perm(old_domain, &r); |
743 | if (retval < 0) | 903 | if (retval < 0) |
744 | goto out; | 904 | goto out; |
745 | 905 | ||
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 2316da8ec5bc..5ae3a571559f 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -14,21 +14,50 @@ | |||
14 | #include "realpath.h" | 14 | #include "realpath.h" |
15 | #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) | 15 | #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) |
16 | 16 | ||
17 | /* Structure for "allow_read" keyword. */ | 17 | /* |
18 | * tomoyo_globally_readable_file_entry is a structure which is used for holding | ||
19 | * "allow_read" entries. | ||
20 | * It has following fields. | ||
21 | * | ||
22 | * (1) "list" which is linked to tomoyo_globally_readable_list . | ||
23 | * (2) "filename" is a pathname which is allowed to open(O_RDONLY). | ||
24 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
25 | * otherwise. | ||
26 | */ | ||
18 | struct tomoyo_globally_readable_file_entry { | 27 | struct tomoyo_globally_readable_file_entry { |
19 | struct list_head list; | 28 | struct list_head list; |
20 | const struct tomoyo_path_info *filename; | 29 | const struct tomoyo_path_info *filename; |
21 | bool is_deleted; | 30 | bool is_deleted; |
22 | }; | 31 | }; |
23 | 32 | ||
24 | /* Structure for "file_pattern" keyword. */ | 33 | /* |
34 | * tomoyo_pattern_entry is a structure which is used for holding | ||
35 | * "tomoyo_pattern_list" entries. | ||
36 | * It has following fields. | ||
37 | * | ||
38 | * (1) "list" which is linked to tomoyo_pattern_list . | ||
39 | * (2) "pattern" is a pathname pattern which is used for converting pathnames | ||
40 | * to pathname patterns during learning mode. | ||
41 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
42 | * otherwise. | ||
43 | */ | ||
25 | struct tomoyo_pattern_entry { | 44 | struct tomoyo_pattern_entry { |
26 | struct list_head list; | 45 | struct list_head list; |
27 | const struct tomoyo_path_info *pattern; | 46 | const struct tomoyo_path_info *pattern; |
28 | bool is_deleted; | 47 | bool is_deleted; |
29 | }; | 48 | }; |
30 | 49 | ||
31 | /* Structure for "deny_rewrite" keyword. */ | 50 | /* |
51 | * tomoyo_no_rewrite_entry is a structure which is used for holding | ||
52 | * "deny_rewrite" entries. | ||
53 | * It has following fields. | ||
54 | * | ||
55 | * (1) "list" which is linked to tomoyo_no_rewrite_list . | ||
56 | * (2) "pattern" is a pathname which is by default not permitted to modify | ||
57 | * already existing content. | ||
58 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
59 | * otherwise. | ||
60 | */ | ||
32 | struct tomoyo_no_rewrite_entry { | 61 | struct tomoyo_no_rewrite_entry { |
33 | struct list_head list; | 62 | struct list_head list; |
34 | const struct tomoyo_path_info *pattern; | 63 | const struct tomoyo_path_info *pattern; |
@@ -141,7 +170,31 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
141 | struct tomoyo_domain_info * | 170 | struct tomoyo_domain_info * |
142 | const domain, const bool is_delete); | 171 | const domain, const bool is_delete); |
143 | 172 | ||
144 | /* The list for "struct tomoyo_globally_readable_file_entry". */ | 173 | /* |
174 | * tomoyo_globally_readable_list is used for holding list of pathnames which | ||
175 | * are by default allowed to be open()ed for reading by any process. | ||
176 | * | ||
177 | * An entry is added by | ||
178 | * | ||
179 | * # echo 'allow_read /lib/libc-2.5.so' > \ | ||
180 | * /sys/kernel/security/tomoyo/exception_policy | ||
181 | * | ||
182 | * and is deleted by | ||
183 | * | ||
184 | * # echo 'delete allow_read /lib/libc-2.5.so' > \ | ||
185 | * /sys/kernel/security/tomoyo/exception_policy | ||
186 | * | ||
187 | * and all entries are retrieved by | ||
188 | * | ||
189 | * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy | ||
190 | * | ||
191 | * In the example above, any process is allowed to | ||
192 | * open("/lib/libc-2.5.so", O_RDONLY). | ||
193 | * One exception is, if the domain which current process belongs to is marked | ||
194 | * as "ignore_global_allow_read", current process can't do so unless explicitly | ||
195 | * given "allow_read /lib/libc-2.5.so" to the domain which current process | ||
196 | * belongs to. | ||
197 | */ | ||
145 | static LIST_HEAD(tomoyo_globally_readable_list); | 198 | static LIST_HEAD(tomoyo_globally_readable_list); |
146 | static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); | 199 | static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); |
147 | 200 | ||
@@ -166,7 +219,6 @@ static int tomoyo_update_globally_readable_entry(const char *filename, | |||
166 | saved_filename = tomoyo_save_name(filename); | 219 | saved_filename = tomoyo_save_name(filename); |
167 | if (!saved_filename) | 220 | if (!saved_filename) |
168 | return -ENOMEM; | 221 | return -ENOMEM; |
169 | /***** EXCLUSIVE SECTION START *****/ | ||
170 | down_write(&tomoyo_globally_readable_list_lock); | 222 | down_write(&tomoyo_globally_readable_list_lock); |
171 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { | 223 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { |
172 | if (ptr->filename != saved_filename) | 224 | if (ptr->filename != saved_filename) |
@@ -187,7 +239,6 @@ static int tomoyo_update_globally_readable_entry(const char *filename, | |||
187 | error = 0; | 239 | error = 0; |
188 | out: | 240 | out: |
189 | up_write(&tomoyo_globally_readable_list_lock); | 241 | up_write(&tomoyo_globally_readable_list_lock); |
190 | /***** EXCLUSIVE SECTION END *****/ | ||
191 | return error; | 242 | return error; |
192 | } | 243 | } |
193 | 244 | ||
@@ -249,17 +300,44 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | |||
249 | list); | 300 | list); |
250 | if (ptr->is_deleted) | 301 | if (ptr->is_deleted) |
251 | continue; | 302 | continue; |
252 | if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", | 303 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", |
253 | ptr->filename->name)) { | 304 | ptr->filename->name); |
254 | done = false; | 305 | if (!done) |
255 | break; | 306 | break; |
256 | } | ||
257 | } | 307 | } |
258 | up_read(&tomoyo_globally_readable_list_lock); | 308 | up_read(&tomoyo_globally_readable_list_lock); |
259 | return done; | 309 | return done; |
260 | } | 310 | } |
261 | 311 | ||
262 | /* The list for "struct tomoyo_pattern_entry". */ | 312 | /* tomoyo_pattern_list is used for holding list of pathnames which are used for |
313 | * converting pathnames to pathname patterns during learning mode. | ||
314 | * | ||
315 | * An entry is added by | ||
316 | * | ||
317 | * # echo 'file_pattern /proc/\$/mounts' > \ | ||
318 | * /sys/kernel/security/tomoyo/exception_policy | ||
319 | * | ||
320 | * and is deleted by | ||
321 | * | ||
322 | * # echo 'delete file_pattern /proc/\$/mounts' > \ | ||
323 | * /sys/kernel/security/tomoyo/exception_policy | ||
324 | * | ||
325 | * and all entries are retrieved by | ||
326 | * | ||
327 | * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy | ||
328 | * | ||
329 | * In the example above, if a process which belongs to a domain which is in | ||
330 | * learning mode requested open("/proc/1/mounts", O_RDONLY), | ||
331 | * "allow_read /proc/\$/mounts" is automatically added to the domain which that | ||
332 | * process belongs to. | ||
333 | * | ||
334 | * It is not a desirable behavior that we have to use /proc/\$/ instead of | ||
335 | * /proc/self/ when current process needs to access only current process's | ||
336 | * information. As of now, LSM version of TOMOYO is using __d_path() for | ||
337 | * calculating pathname. Non LSM version of TOMOYO is using its own function | ||
338 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid | ||
339 | * current process from accessing other process's information. | ||
340 | */ | ||
263 | static LIST_HEAD(tomoyo_pattern_list); | 341 | static LIST_HEAD(tomoyo_pattern_list); |
264 | static DECLARE_RWSEM(tomoyo_pattern_list_lock); | 342 | static DECLARE_RWSEM(tomoyo_pattern_list_lock); |
265 | 343 | ||
@@ -284,7 +362,6 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, | |||
284 | saved_pattern = tomoyo_save_name(pattern); | 362 | saved_pattern = tomoyo_save_name(pattern); |
285 | if (!saved_pattern) | 363 | if (!saved_pattern) |
286 | return -ENOMEM; | 364 | return -ENOMEM; |
287 | /***** EXCLUSIVE SECTION START *****/ | ||
288 | down_write(&tomoyo_pattern_list_lock); | 365 | down_write(&tomoyo_pattern_list_lock); |
289 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { | 366 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { |
290 | if (saved_pattern != ptr->pattern) | 367 | if (saved_pattern != ptr->pattern) |
@@ -305,7 +382,6 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, | |||
305 | error = 0; | 382 | error = 0; |
306 | out: | 383 | out: |
307 | up_write(&tomoyo_pattern_list_lock); | 384 | up_write(&tomoyo_pattern_list_lock); |
308 | /***** EXCLUSIVE SECTION END *****/ | ||
309 | return error; | 385 | return error; |
310 | } | 386 | } |
311 | 387 | ||
@@ -373,17 +449,44 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | |||
373 | ptr = list_entry(pos, struct tomoyo_pattern_entry, list); | 449 | ptr = list_entry(pos, struct tomoyo_pattern_entry, list); |
374 | if (ptr->is_deleted) | 450 | if (ptr->is_deleted) |
375 | continue; | 451 | continue; |
376 | if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN "%s\n", | 452 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN |
377 | ptr->pattern->name)) { | 453 | "%s\n", ptr->pattern->name); |
378 | done = false; | 454 | if (!done) |
379 | break; | 455 | break; |
380 | } | ||
381 | } | 456 | } |
382 | up_read(&tomoyo_pattern_list_lock); | 457 | up_read(&tomoyo_pattern_list_lock); |
383 | return done; | 458 | return done; |
384 | } | 459 | } |
385 | 460 | ||
386 | /* The list for "struct tomoyo_no_rewrite_entry". */ | 461 | /* |
462 | * tomoyo_no_rewrite_list is used for holding list of pathnames which are by | ||
463 | * default forbidden to modify already written content of a file. | ||
464 | * | ||
465 | * An entry is added by | ||
466 | * | ||
467 | * # echo 'deny_rewrite /var/log/messages' > \ | ||
468 | * /sys/kernel/security/tomoyo/exception_policy | ||
469 | * | ||
470 | * and is deleted by | ||
471 | * | ||
472 | * # echo 'delete deny_rewrite /var/log/messages' > \ | ||
473 | * /sys/kernel/security/tomoyo/exception_policy | ||
474 | * | ||
475 | * and all entries are retrieved by | ||
476 | * | ||
477 | * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy | ||
478 | * | ||
479 | * In the example above, if a process requested to rewrite /var/log/messages , | ||
480 | * the process can't rewrite unless the domain which that process belongs to | ||
481 | * has "allow_rewrite /var/log/messages" entry. | ||
482 | * | ||
483 | * It is not a desirable behavior that we have to add "\040(deleted)" suffix | ||
484 | * when we want to allow rewriting already unlink()ed file. As of now, | ||
485 | * LSM version of TOMOYO is using __d_path() for calculating pathname. | ||
486 | * Non LSM version of TOMOYO is using its own function which doesn't append | ||
487 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't | ||
488 | * need to worry whether the file is already unlink()ed or not. | ||
489 | */ | ||
387 | static LIST_HEAD(tomoyo_no_rewrite_list); | 490 | static LIST_HEAD(tomoyo_no_rewrite_list); |
388 | static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); | 491 | static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); |
389 | 492 | ||
@@ -407,7 +510,6 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, | |||
407 | saved_pattern = tomoyo_save_name(pattern); | 510 | saved_pattern = tomoyo_save_name(pattern); |
408 | if (!saved_pattern) | 511 | if (!saved_pattern) |
409 | return -ENOMEM; | 512 | return -ENOMEM; |
410 | /***** EXCLUSIVE SECTION START *****/ | ||
411 | down_write(&tomoyo_no_rewrite_list_lock); | 513 | down_write(&tomoyo_no_rewrite_list_lock); |
412 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { | 514 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { |
413 | if (ptr->pattern != saved_pattern) | 515 | if (ptr->pattern != saved_pattern) |
@@ -428,7 +530,6 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, | |||
428 | error = 0; | 530 | error = 0; |
429 | out: | 531 | out: |
430 | up_write(&tomoyo_no_rewrite_list_lock); | 532 | up_write(&tomoyo_no_rewrite_list_lock); |
431 | /***** EXCLUSIVE SECTION END *****/ | ||
432 | return error; | 533 | return error; |
433 | } | 534 | } |
434 | 535 | ||
@@ -489,11 +590,10 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | |||
489 | ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); | 590 | ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); |
490 | if (ptr->is_deleted) | 591 | if (ptr->is_deleted) |
491 | continue; | 592 | continue; |
492 | if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE "%s\n", | 593 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE |
493 | ptr->pattern->name)) { | 594 | "%s\n", ptr->pattern->name); |
494 | done = false; | 595 | if (!done) |
495 | break; | 596 | break; |
496 | } | ||
497 | } | 597 | } |
498 | up_read(&tomoyo_no_rewrite_list_lock); | 598 | up_read(&tomoyo_no_rewrite_list_lock); |
499 | return done; | 599 | return done; |
@@ -745,7 +845,6 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
745 | saved_filename = tomoyo_save_name(filename); | 845 | saved_filename = tomoyo_save_name(filename); |
746 | if (!saved_filename) | 846 | if (!saved_filename) |
747 | return -ENOMEM; | 847 | return -ENOMEM; |
748 | /***** EXCLUSIVE SECTION START *****/ | ||
749 | down_write(&tomoyo_domain_acl_info_list_lock); | 848 | down_write(&tomoyo_domain_acl_info_list_lock); |
750 | if (is_delete) | 849 | if (is_delete) |
751 | goto delete; | 850 | goto delete; |
@@ -800,7 +899,6 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
800 | } | 899 | } |
801 | out: | 900 | out: |
802 | up_write(&tomoyo_domain_acl_info_list_lock); | 901 | up_write(&tomoyo_domain_acl_info_list_lock); |
803 | /***** EXCLUSIVE SECTION END *****/ | ||
804 | return error; | 902 | return error; |
805 | } | 903 | } |
806 | 904 | ||
@@ -836,7 +934,6 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | |||
836 | saved_filename2 = tomoyo_save_name(filename2); | 934 | saved_filename2 = tomoyo_save_name(filename2); |
837 | if (!saved_filename1 || !saved_filename2) | 935 | if (!saved_filename1 || !saved_filename2) |
838 | return -ENOMEM; | 936 | return -ENOMEM; |
839 | /***** EXCLUSIVE SECTION START *****/ | ||
840 | down_write(&tomoyo_domain_acl_info_list_lock); | 937 | down_write(&tomoyo_domain_acl_info_list_lock); |
841 | if (is_delete) | 938 | if (is_delete) |
842 | goto delete; | 939 | goto delete; |
@@ -884,7 +981,6 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | |||
884 | } | 981 | } |
885 | out: | 982 | out: |
886 | up_write(&tomoyo_domain_acl_info_list_lock); | 983 | up_write(&tomoyo_domain_acl_info_list_lock); |
887 | /***** EXCLUSIVE SECTION END *****/ | ||
888 | return error; | 984 | return error; |
889 | } | 985 | } |
890 | 986 | ||
@@ -1025,13 +1121,11 @@ int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, | |||
1025 | * | 1121 | * |
1026 | * @domain: Pointer to "struct tomoyo_domain_info". | 1122 | * @domain: Pointer to "struct tomoyo_domain_info". |
1027 | * @filename: Check permission for "execute". | 1123 | * @filename: Check permission for "execute". |
1028 | * @tmp: Buffer for temporary use. | ||
1029 | * | 1124 | * |
1030 | * Returns 0 on success, negativevalue otherwise. | 1125 | * Returns 0 on success, negativevalue otherwise. |
1031 | */ | 1126 | */ |
1032 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | 1127 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, |
1033 | const struct tomoyo_path_info *filename, | 1128 | const struct tomoyo_path_info *filename) |
1034 | struct tomoyo_page_buffer *tmp) | ||
1035 | { | 1129 | { |
1036 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1130 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1037 | 1131 | ||
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 40927a84cb6e..5f2e33263371 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -220,7 +220,6 @@ void *tomoyo_alloc_element(const unsigned int size) | |||
220 | = roundup(size, max(sizeof(void *), sizeof(long))); | 220 | = roundup(size, max(sizeof(void *), sizeof(long))); |
221 | if (word_aligned_size > PATH_MAX) | 221 | if (word_aligned_size > PATH_MAX) |
222 | return NULL; | 222 | return NULL; |
223 | /***** EXCLUSIVE SECTION START *****/ | ||
224 | mutex_lock(&lock); | 223 | mutex_lock(&lock); |
225 | if (buf_used_len + word_aligned_size > PATH_MAX) { | 224 | if (buf_used_len + word_aligned_size > PATH_MAX) { |
226 | if (!tomoyo_quota_for_elements || | 225 | if (!tomoyo_quota_for_elements || |
@@ -251,7 +250,6 @@ void *tomoyo_alloc_element(const unsigned int size) | |||
251 | } | 250 | } |
252 | } | 251 | } |
253 | mutex_unlock(&lock); | 252 | mutex_unlock(&lock); |
254 | /***** EXCLUSIVE SECTION END *****/ | ||
255 | return ptr; | 253 | return ptr; |
256 | } | 254 | } |
257 | 255 | ||
@@ -267,7 +265,16 @@ static unsigned int tomoyo_quota_for_savename; | |||
267 | */ | 265 | */ |
268 | #define TOMOYO_MAX_HASH 256 | 266 | #define TOMOYO_MAX_HASH 256 |
269 | 267 | ||
270 | /* Structure for string data. */ | 268 | /* |
269 | * tomoyo_name_entry is a structure which is used for linking | ||
270 | * "struct tomoyo_path_info" into tomoyo_name_list . | ||
271 | * | ||
272 | * Since tomoyo_name_list manages a list of strings which are shared by | ||
273 | * multiple processes (whereas "struct tomoyo_path_info" inside | ||
274 | * "struct tomoyo_path_info_with_data" is not shared), a reference counter will | ||
275 | * be added to "struct tomoyo_name_entry" rather than "struct tomoyo_path_info" | ||
276 | * when TOMOYO starts supporting garbage collector. | ||
277 | */ | ||
271 | struct tomoyo_name_entry { | 278 | struct tomoyo_name_entry { |
272 | struct list_head list; | 279 | struct list_head list; |
273 | struct tomoyo_path_info entry; | 280 | struct tomoyo_path_info entry; |
@@ -281,10 +288,10 @@ struct tomoyo_free_memory_block_list { | |||
281 | }; | 288 | }; |
282 | 289 | ||
283 | /* | 290 | /* |
284 | * The list for "struct tomoyo_name_entry". | 291 | * tomoyo_name_list is used for holding string data used by TOMOYO. |
285 | * | 292 | * Since same string data is likely used for multiple times (e.g. |
286 | * This list is updated only inside tomoyo_save_name(), thus | 293 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of |
287 | * no global mutex exists. | 294 | * "const struct tomoyo_path_info *". |
288 | */ | 295 | */ |
289 | static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 296 | static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
290 | 297 | ||
@@ -318,7 +325,6 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name) | |||
318 | return NULL; | 325 | return NULL; |
319 | } | 326 | } |
320 | hash = full_name_hash((const unsigned char *) name, len - 1); | 327 | hash = full_name_hash((const unsigned char *) name, len - 1); |
321 | /***** EXCLUSIVE SECTION START *****/ | ||
322 | mutex_lock(&lock); | 328 | mutex_lock(&lock); |
323 | list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH], | 329 | list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH], |
324 | list) { | 330 | list) { |
@@ -366,7 +372,6 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name) | |||
366 | } | 372 | } |
367 | out: | 373 | out: |
368 | mutex_unlock(&lock); | 374 | mutex_unlock(&lock); |
369 | /***** EXCLUSIVE SECTION END *****/ | ||
370 | return ptr ? &ptr->entry : NULL; | 375 | return ptr ? &ptr->entry : NULL; |
371 | } | 376 | } |
372 | 377 | ||
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index e42be5c4f055..3194d09fe0f4 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -262,6 +262,10 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | |||
262 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); | 262 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); |
263 | } | 263 | } |
264 | 264 | ||
265 | /* | ||
266 | * tomoyo_security_ops is a "struct security_operations" which is used for | ||
267 | * registering TOMOYO. | ||
268 | */ | ||
265 | static struct security_operations tomoyo_security_ops = { | 269 | static struct security_operations tomoyo_security_ops = { |
266 | .name = "tomoyo", | 270 | .name = "tomoyo", |
267 | .cred_prepare = tomoyo_cred_prepare, | 271 | .cred_prepare = tomoyo_cred_prepare, |
diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h index 41c6ebafb9c5..0fd588a629cf 100644 --- a/security/tomoyo/tomoyo.h +++ b/security/tomoyo/tomoyo.h | |||
@@ -17,13 +17,11 @@ struct path; | |||
17 | struct inode; | 17 | struct inode; |
18 | struct linux_binprm; | 18 | struct linux_binprm; |
19 | struct pt_regs; | 19 | struct pt_regs; |
20 | struct tomoyo_page_buffer; | ||
21 | 20 | ||
22 | int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, | 21 | int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, |
23 | const char *filename, const u8 perm); | 22 | const char *filename, const u8 perm); |
24 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | 23 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, |
25 | const struct tomoyo_path_info *filename, | 24 | const struct tomoyo_path_info *filename); |
26 | struct tomoyo_page_buffer *buf); | ||
27 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | 25 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, |
28 | struct path *path, const int flag); | 26 | struct path *path, const int flag); |
29 | int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | 27 | int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, |
@@ -90,17 +88,10 @@ static inline struct tomoyo_domain_info *tomoyo_domain(void) | |||
90 | return current_cred()->security; | 88 | return current_cred()->security; |
91 | } | 89 | } |
92 | 90 | ||
93 | /* Caller holds tasklist_lock spinlock. */ | ||
94 | static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct | 91 | static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct |
95 | *task) | 92 | *task) |
96 | { | 93 | { |
97 | /***** CRITICAL SECTION START *****/ | 94 | return task_cred_xxx(task, security); |
98 | const struct cred *cred = get_task_cred(task); | ||
99 | struct tomoyo_domain_info *domain = cred->security; | ||
100 | |||
101 | put_cred(cred); | ||
102 | return domain; | ||
103 | /***** CRITICAL SECTION END *****/ | ||
104 | } | 95 | } |
105 | 96 | ||
106 | #endif /* !defined(_SECURITY_TOMOYO_TOMOYO_H) */ | 97 | #endif /* !defined(_SECURITY_TOMOYO_TOMOYO_H) */ |