Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6:
selinux: Fix an uninitialized variable BUG/panic in selinux_secattr_to_sid()
selinux: use default proc sid on symlinks
file capabilities: uninline cap_safe_nice
Update selinux info in MAINTAINERS and Kconfig help text
SELinux: add gitignore file for mdp script
SELinux: add boundary support and thread context assignment
securityfs: do not depend on CONFIG_SECURITY
selinux: add support for installing a dummy policy (v2)
security: add/fix security kernel-doc
selinux: Unify for- and while-loop style
selinux: conditional expression type validation was off-by-one
smack: limit privilege by label
SELinux: Fix a potentially uninitialised variable in SELinux hooks
SELinux: trivial, remove unneeded local variable
SELinux: Trivial minor fixes that change C null character style
make selinux_write_opts() static

+995 -141
+1
Documentation/DocBook/kernel-api.tmpl
··· 283 283 <chapter id="security"> 284 284 <title>Security Framework</title> 285 285 !Isecurity/security.c 286 + !Esecurity/inode.c 286 287 </chapter> 287 288 288 289 <chapter id="audit">
+27
Documentation/SELinux.txt
··· 1 + If you want to use SELinux, chances are you will want 2 + to use the distro-provided policies, or install the 3 + latest reference policy release from 4 + http://oss.tresys.com/projects/refpolicy 5 + 6 + However, if you want to install a dummy policy for 7 + testing, you can do using 'mdp' provided under 8 + scripts/selinux. Note that this requires the selinux 9 + userspace to be installed - in particular you will 10 + need checkpolicy to compile a kernel, and setfiles and 11 + fixfiles to label the filesystem. 12 + 13 + 1. Compile the kernel with selinux enabled. 14 + 2. Type 'make' to compile mdp. 15 + 3. Make sure that you are not running with 16 + SELinux enabled and a real policy. If 17 + you are, reboot with selinux disabled 18 + before continuing. 19 + 4. Run install_policy.sh: 20 + cd scripts/selinux 21 + sh install_policy.sh 22 + 23 + Step 4 will create a new dummy policy valid for your 24 + kernel, with a single selinux user, role, and type. 25 + It will compile the policy, will set your SELINUXTYPE to 26 + dummy in /etc/selinux/config, install the compiled policy 27 + as 'dummy', and relabel your filesystem.
+3 -2
MAINTAINERS
··· 3649 3649 P: Eric Paris 3650 3650 M: eparis@parisplace.org 3651 3651 L: linux-kernel@vger.kernel.org (kernel issues) 3652 - L: selinux@tycho.nsa.gov (subscribers-only, general discussion) 3653 - W: http://www.nsa.gov/selinux 3652 + L: selinux@tycho.nsa.gov (subscribers-only, general discussion) 3653 + W: http://selinuxproject.org 3654 + T: git kernel.org:pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git 3654 3655 S: Supported 3655 3656 3656 3657 SENSABLE PHANTOM
+1
drivers/char/tpm/Kconfig
··· 6 6 tristate "TPM Hardware Support" 7 7 depends on HAS_IOMEM 8 8 depends on EXPERIMENTAL 9 + select SECURITYFS 9 10 ---help--- 10 11 If you have a TPM security chip in your system, which 11 12 implements the Trusted Computing Group's specification,
+30 -24
include/linux/security.h
··· 1560 1560 extern int security_init(void); 1561 1561 extern int security_module_enable(struct security_operations *ops); 1562 1562 extern int register_security(struct security_operations *ops); 1563 - extern struct dentry *securityfs_create_file(const char *name, mode_t mode, 1564 - struct dentry *parent, void *data, 1565 - const struct file_operations *fops); 1566 - extern struct dentry *securityfs_create_dir(const char *name, struct dentry *parent); 1567 - extern void securityfs_remove(struct dentry *dentry); 1568 1563 1569 1564 /* Security operations */ 1570 1565 int security_ptrace_may_access(struct task_struct *child, unsigned int mode); ··· 2419 2424 return cap_netlink_recv(skb, cap); 2420 2425 } 2421 2426 2422 - static inline struct dentry *securityfs_create_dir(const char *name, 2423 - struct dentry *parent) 2424 - { 2425 - return ERR_PTR(-ENODEV); 2426 - } 2427 - 2428 - static inline struct dentry *securityfs_create_file(const char *name, 2429 - mode_t mode, 2430 - struct dentry *parent, 2431 - void *data, 2432 - const struct file_operations *fops) 2433 - { 2434 - return ERR_PTR(-ENODEV); 2435 - } 2436 - 2437 - static inline void securityfs_remove(struct dentry *dentry) 2438 - { 2439 - } 2440 - 2441 2427 static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) 2442 2428 { 2443 2429 return -EOPNOTSUPP; ··· 2781 2805 2782 2806 #endif /* CONFIG_SECURITY */ 2783 2807 #endif /* CONFIG_AUDIT */ 2808 + 2809 + #ifdef CONFIG_SECURITYFS 2810 + 2811 + extern struct dentry *securityfs_create_file(const char *name, mode_t mode, 2812 + struct dentry *parent, void *data, 2813 + const struct file_operations *fops); 2814 + extern struct dentry *securityfs_create_dir(const char *name, struct dentry *parent); 2815 + extern void securityfs_remove(struct dentry *dentry); 2816 + 2817 + #else /* CONFIG_SECURITYFS */ 2818 + 2819 + static inline struct dentry *securityfs_create_dir(const char *name, 2820 + struct dentry *parent) 2821 + { 2822 + return ERR_PTR(-ENODEV); 2823 + } 2824 + 2825 + static inline struct dentry *securityfs_create_file(const char *name, 2826 + mode_t mode, 2827 + struct dentry *parent, 2828 + void *data, 2829 + const struct file_operations *fops) 2830 + { 2831 + return ERR_PTR(-ENODEV); 2832 + } 2833 + 2834 + static inline void securityfs_remove(struct dentry *dentry) 2835 + {} 2836 + 2837 + #endif 2784 2838 2785 2839 #endif /* ! __LINUX_SECURITY_H */ 2786 2840
+2 -1
scripts/Makefile
··· 20 20 21 21 subdir-$(CONFIG_MODVERSIONS) += genksyms 22 22 subdir-y += mod 23 + subdir-$(CONFIG_SECURITY_SELINUX) += selinux 23 24 24 25 # Let clean descend into subdirs 25 - subdir- += basic kconfig package 26 + subdir- += basic kconfig package selinux
+2
scripts/selinux/Makefile
··· 1 + subdir-y := mdp 2 + subdir- += mdp
+2
scripts/selinux/README
··· 1 + Please see Documentation/SELinux.txt for information on 2 + installing a dummy SELinux policy.
+69
scripts/selinux/install_policy.sh
··· 1 + #!/bin/sh 2 + if [ `id -u` -ne 0 ]; then 3 + echo "$0: must be root to install the selinux policy" 4 + exit 1 5 + fi 6 + SF=`which setfiles` 7 + if [ $? -eq 1 ]; then 8 + if [ -f /sbin/setfiles ]; then 9 + SF="/usr/setfiles" 10 + else 11 + echo "no selinux tools installed: setfiles" 12 + exit 1 13 + fi 14 + fi 15 + 16 + cd mdp 17 + 18 + CP=`which checkpolicy` 19 + VERS=`$CP -V | awk '{print $1}'` 20 + 21 + ./mdp policy.conf file_contexts 22 + $CP -o policy.$VERS policy.conf 23 + 24 + mkdir -p /etc/selinux/dummy/policy 25 + mkdir -p /etc/selinux/dummy/contexts/files 26 + 27 + cp file_contexts /etc/selinux/dummy/contexts/files 28 + cp dbus_contexts /etc/selinux/dummy/contexts 29 + cp policy.$VERS /etc/selinux/dummy/policy 30 + FC_FILE=/etc/selinux/dummy/contexts/files/file_contexts 31 + 32 + if [ ! -d /etc/selinux ]; then 33 + mkdir -p /etc/selinux 34 + fi 35 + if [ ! -f /etc/selinux/config ]; then 36 + cat > /etc/selinux/config << EOF 37 + SELINUX=enforcing 38 + SELINUXTYPE=dummy 39 + EOF 40 + else 41 + TYPE=`cat /etc/selinux/config | grep "^SELINUXTYPE" | tail -1 | awk -F= '{ print $2 '}` 42 + if [ "eq$TYPE" != "eqdummy" ]; then 43 + selinuxenabled 44 + if [ $? -eq 0 ]; then 45 + echo "SELinux already enabled with a non-dummy policy." 46 + echo "Exiting. Please install policy by hand if that" 47 + echo "is what you REALLY want." 48 + exit 1 49 + fi 50 + mv /etc/selinux/config /etc/selinux/config.mdpbak 51 + grep -v "^SELINUXTYPE" /etc/selinux/config.mdpbak >> /etc/selinux/config 52 + echo "SELINUXTYPE=dummy" >> /etc/selinux/config 53 + fi 54 + fi 55 + 56 + cd /etc/selinux/dummy/contexts/files 57 + $SF file_contexts / 58 + 59 + mounts=`cat /proc/$$/mounts | egrep "ext2|ext3|xfs|jfs|ext4|ext4dev|gfs2" | awk '{ print $2 '}` 60 + $SF file_contexts $mounts 61 + 62 + 63 + dodev=`cat /proc/$$/mounts | grep "/dev "` 64 + if [ "eq$dodev" != "eq" ]; then 65 + mount --move /dev /mnt 66 + $SF file_contexts /dev 67 + mount --move /mnt /dev 68 + fi 69 +
+2
scripts/selinux/mdp/.gitignore
··· 1 + # Generated file 2 + mdp
+5
scripts/selinux/mdp/Makefile
··· 1 + hostprogs-y := mdp 2 + HOST_EXTRACFLAGS += -Isecurity/selinux/include 3 + 4 + always := $(hostprogs-y) 5 + clean-files := $(hostprogs-y) policy.* file_contexts
+6
scripts/selinux/mdp/dbus_contexts
··· 1 + <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" 2 + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> 3 + <busconfig> 4 + <selinux> 5 + </selinux> 6 + </busconfig>
+242
scripts/selinux/mdp/mdp.c
··· 1 + /* 2 + * 3 + * mdp - make dummy policy 4 + * 5 + * When pointed at a kernel tree, builds a dummy policy for that kernel 6 + * with exactly one type with full rights to itself. 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; either version 2 of the License, or 11 + * (at your option) any later version. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License 19 + * along with this program; if not, write to the Free Software 20 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 21 + * 22 + * Copyright (C) IBM Corporation, 2006 23 + * 24 + * Authors: Serge E. Hallyn <serue@us.ibm.com> 25 + */ 26 + 27 + #include <stdio.h> 28 + #include <stdlib.h> 29 + #include <unistd.h> 30 + #include <string.h> 31 + 32 + #include "flask.h" 33 + 34 + void usage(char *name) 35 + { 36 + printf("usage: %s [-m] policy_file context_file\n", name); 37 + exit(1); 38 + } 39 + 40 + void find_common_name(char *cname, char *dest, int len) 41 + { 42 + char *start, *end; 43 + 44 + start = strchr(cname, '_')+1; 45 + end = strchr(start, '_'); 46 + if (!start || !end || start-cname > len || end-start > len) { 47 + printf("Error with commons defines\n"); 48 + exit(1); 49 + } 50 + strncpy(dest, start, end-start); 51 + dest[end-start] = '\0'; 52 + } 53 + 54 + #define S_(x) x, 55 + static char *classlist[] = { 56 + #include "class_to_string.h" 57 + NULL 58 + }; 59 + #undef S_ 60 + 61 + #include "initial_sid_to_string.h" 62 + 63 + #define TB_(x) char *x[] = { 64 + #define TE_(x) NULL }; 65 + #define S_(x) x, 66 + #include "common_perm_to_string.h" 67 + #undef TB_ 68 + #undef TE_ 69 + #undef S_ 70 + 71 + struct common { 72 + char *cname; 73 + char **perms; 74 + }; 75 + struct common common[] = { 76 + #define TB_(x) { #x, x }, 77 + #define S_(x) 78 + #define TE_(x) 79 + #include "common_perm_to_string.h" 80 + #undef TB_ 81 + #undef TE_ 82 + #undef S_ 83 + }; 84 + 85 + #define S_(x, y, z) {x, #y}, 86 + struct av_inherit { 87 + int class; 88 + char *common; 89 + }; 90 + struct av_inherit av_inherit[] = { 91 + #include "av_inherit.h" 92 + }; 93 + #undef S_ 94 + 95 + #include "av_permissions.h" 96 + #define S_(x, y, z) {x, y, z}, 97 + struct av_perms { 98 + int class; 99 + int perm_i; 100 + char *perm_s; 101 + }; 102 + struct av_perms av_perms[] = { 103 + #include "av_perm_to_string.h" 104 + }; 105 + #undef S_ 106 + 107 + int main(int argc, char *argv[]) 108 + { 109 + int i, j, mls = 0; 110 + char **arg, *polout, *ctxout; 111 + int classlist_len, initial_sid_to_string_len; 112 + FILE *fout; 113 + 114 + if (argc < 3) 115 + usage(argv[0]); 116 + arg = argv+1; 117 + if (argc==4 && strcmp(argv[1], "-m") == 0) { 118 + mls = 1; 119 + arg++; 120 + } 121 + polout = *arg++; 122 + ctxout = *arg; 123 + 124 + fout = fopen(polout, "w"); 125 + if (!fout) { 126 + printf("Could not open %s for writing\n", polout); 127 + usage(argv[0]); 128 + } 129 + 130 + classlist_len = sizeof(classlist) / sizeof(char *); 131 + /* print out the classes */ 132 + for (i=1; i < classlist_len; i++) { 133 + if(classlist[i]) 134 + fprintf(fout, "class %s\n", classlist[i]); 135 + else 136 + fprintf(fout, "class user%d\n", i); 137 + } 138 + fprintf(fout, "\n"); 139 + 140 + initial_sid_to_string_len = sizeof(initial_sid_to_string) / sizeof (char *); 141 + /* print out the sids */ 142 + for (i=1; i < initial_sid_to_string_len; i++) 143 + fprintf(fout, "sid %s\n", initial_sid_to_string[i]); 144 + fprintf(fout, "\n"); 145 + 146 + /* print out the commons */ 147 + for (i=0; i< sizeof(common)/sizeof(struct common); i++) { 148 + char cname[101]; 149 + find_common_name(common[i].cname, cname, 100); 150 + cname[100] = '\0'; 151 + fprintf(fout, "common %s\n{\n", cname); 152 + for (j=0; common[i].perms[j]; j++) 153 + fprintf(fout, "\t%s\n", common[i].perms[j]); 154 + fprintf(fout, "}\n\n"); 155 + } 156 + fprintf(fout, "\n"); 157 + 158 + /* print out the class permissions */ 159 + for (i=1; i < classlist_len; i++) { 160 + if (classlist[i]) { 161 + int firstperm = -1, numperms = 0; 162 + 163 + fprintf(fout, "class %s\n", classlist[i]); 164 + /* does it inherit from a common? */ 165 + for (j=0; j < sizeof(av_inherit)/sizeof(struct av_inherit); j++) 166 + if (av_inherit[j].class == i) 167 + fprintf(fout, "inherits %s\n", av_inherit[j].common); 168 + 169 + for (j=0; j < sizeof(av_perms)/sizeof(struct av_perms); j++) { 170 + if (av_perms[j].class == i) { 171 + if (firstperm == -1) 172 + firstperm = j; 173 + numperms++; 174 + } 175 + } 176 + if (!numperms) { 177 + fprintf(fout, "\n"); 178 + continue; 179 + } 180 + 181 + fprintf(fout, "{\n"); 182 + /* print out the av_perms */ 183 + for (j=0; j < numperms; j++) { 184 + fprintf(fout, "\t%s\n", av_perms[firstperm+j].perm_s); 185 + } 186 + fprintf(fout, "}\n\n"); 187 + } 188 + } 189 + fprintf(fout, "\n"); 190 + 191 + /* NOW PRINT OUT MLS STUFF */ 192 + if (mls) { 193 + printf("MLS not yet implemented\n"); 194 + exit(1); 195 + } 196 + 197 + /* types, roles, and allows */ 198 + fprintf(fout, "type base_t;\n"); 199 + fprintf(fout, "role base_r types { base_t };\n"); 200 + for (i=1; i < classlist_len; i++) { 201 + if (classlist[i]) 202 + fprintf(fout, "allow base_t base_t:%s *;\n", classlist[i]); 203 + else 204 + fprintf(fout, "allow base_t base_t:user%d *;\n", i); 205 + } 206 + fprintf(fout, "user user_u roles { base_r };\n"); 207 + fprintf(fout, "\n"); 208 + 209 + /* default sids */ 210 + for (i=1; i < initial_sid_to_string_len; i++) 211 + fprintf(fout, "sid %s user_u:base_r:base_t\n", initial_sid_to_string[i]); 212 + fprintf(fout, "\n"); 213 + 214 + 215 + fprintf(fout, "fs_use_xattr ext2 user_u:base_r:base_t;\n"); 216 + fprintf(fout, "fs_use_xattr ext3 user_u:base_r:base_t;\n"); 217 + fprintf(fout, "fs_use_xattr jfs user_u:base_r:base_t;\n"); 218 + fprintf(fout, "fs_use_xattr xfs user_u:base_r:base_t;\n"); 219 + fprintf(fout, "fs_use_xattr reiserfs user_u:base_r:base_t;\n"); 220 + 221 + fprintf(fout, "fs_use_task pipefs user_u:base_r:base_t;\n"); 222 + fprintf(fout, "fs_use_task sockfs user_u:base_r:base_t;\n"); 223 + 224 + fprintf(fout, "fs_use_trans devpts user_u:base_r:base_t;\n"); 225 + fprintf(fout, "fs_use_trans tmpfs user_u:base_r:base_t;\n"); 226 + fprintf(fout, "fs_use_trans shm user_u:base_r:base_t;\n"); 227 + 228 + fprintf(fout, "genfscon proc / user_u:base_r:base_t\n"); 229 + 230 + fclose(fout); 231 + 232 + fout = fopen(ctxout, "w"); 233 + if (!fout) { 234 + printf("Wrote policy, but cannot open %s for writing\n", ctxout); 235 + usage(argv[0]); 236 + } 237 + fprintf(fout, "/ user_u:base_r:base_t\n"); 238 + fprintf(fout, "/.* user_u:base_r:base_t\n"); 239 + fclose(fout); 240 + 241 + return 0; 242 + }
+8
security/Kconfig
··· 51 51 52 52 If you are unsure how to answer this question, answer N. 53 53 54 + config SECURITYFS 55 + bool "Enable the securityfs filesystem" 56 + help 57 + This will build the securityfs filesystem. It is currently used by 58 + the TPM bios character driver. It is not used by SELinux or SMACK. 59 + 60 + If you are unsure how to answer this question, answer N. 61 + 54 62 config SECURITY_NETWORK 55 63 bool "Socket and Networking Security Hooks" 56 64 depends on SECURITY
+2 -1
security/Makefile
··· 10 10 obj-y += commoncap.o 11 11 12 12 # Object file lists 13 - obj-$(CONFIG_SECURITY) += security.o capability.o inode.o 13 + obj-$(CONFIG_SECURITY) += security.o capability.o 14 + obj-$(CONFIG_SECURITYFS) += inode.o 14 15 # Must precede capability.o in order to stack properly. 15 16 obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o 16 17 obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
+1 -1
security/commoncap.c
··· 541 541 * yet with increased caps. 542 542 * So we check for increased caps on the target process. 543 543 */ 544 - static inline int cap_safe_nice(struct task_struct *p) 544 + static int cap_safe_nice(struct task_struct *p) 545 545 { 546 546 if (!cap_issubset(p->cap_permitted, current->cap_permitted) && 547 547 !capable(CAP_SYS_NICE))
+16 -17
security/inode.c
··· 190 190 * @name: a pointer to a string containing the name of the file to create. 191 191 * @mode: the permission that the file should have 192 192 * @parent: a pointer to the parent dentry for this file. This should be a 193 - * directory dentry if set. If this paramater is NULL, then the 193 + * directory dentry if set. If this parameter is %NULL, then the 194 194 * file will be created in the root of the securityfs filesystem. 195 195 * @data: a pointer to something that the caller will want to get to later 196 196 * on. The inode.i_private pointer will point to this value on ··· 199 199 * this file. 200 200 * 201 201 * This is the basic "create a file" function for securityfs. It allows for a 202 - * wide range of flexibility in createing a file, or a directory (if you 202 + * wide range of flexibility in creating a file, or a directory (if you 203 203 * want to create a directory, the securityfs_create_dir() function is 204 - * recommended to be used instead.) 204 + * recommended to be used instead). 205 205 * 206 - * This function will return a pointer to a dentry if it succeeds. This 206 + * This function returns a pointer to a dentry if it succeeds. This 207 207 * pointer must be passed to the securityfs_remove() function when the file is 208 208 * to be removed (no automatic cleanup happens if your module is unloaded, 209 - * you are responsible here.) If an error occurs, NULL will be returned. 209 + * you are responsible here). If an error occurs, %NULL is returned. 210 210 * 211 - * If securityfs is not enabled in the kernel, the value -ENODEV will be 211 + * If securityfs is not enabled in the kernel, the value %-ENODEV is 212 212 * returned. It is not wise to check for this value, but rather, check for 213 - * NULL or !NULL instead as to eliminate the need for #ifdef in the calling 213 + * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling 214 214 * code. 215 215 */ 216 216 struct dentry *securityfs_create_file(const char *name, mode_t mode, ··· 252 252 * @name: a pointer to a string containing the name of the directory to 253 253 * create. 254 254 * @parent: a pointer to the parent dentry for this file. This should be a 255 - * directory dentry if set. If this paramater is NULL, then the 255 + * directory dentry if set. If this parameter is %NULL, then the 256 256 * directory will be created in the root of the securityfs filesystem. 257 257 * 258 - * This function creates a directory in securityfs with the given name. 258 + * This function creates a directory in securityfs with the given @name. 259 259 * 260 - * This function will return a pointer to a dentry if it succeeds. This 260 + * This function returns a pointer to a dentry if it succeeds. This 261 261 * pointer must be passed to the securityfs_remove() function when the file is 262 262 * to be removed (no automatic cleanup happens if your module is unloaded, 263 - * you are responsible here.) If an error occurs, NULL will be returned. 263 + * you are responsible here). If an error occurs, %NULL will be returned. 264 264 * 265 - * If securityfs is not enabled in the kernel, the value -ENODEV will be 265 + * If securityfs is not enabled in the kernel, the value %-ENODEV is 266 266 * returned. It is not wise to check for this value, but rather, check for 267 - * NULL or !NULL instead as to eliminate the need for #ifdef in the calling 267 + * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling 268 268 * code. 269 269 */ 270 270 struct dentry *securityfs_create_dir(const char *name, struct dentry *parent) ··· 278 278 /** 279 279 * securityfs_remove - removes a file or directory from the securityfs filesystem 280 280 * 281 - * @dentry: a pointer to a the dentry of the file or directory to be 282 - * removed. 281 + * @dentry: a pointer to a the dentry of the file or directory to be removed. 283 282 * 284 283 * This function removes a file or directory in securityfs that was previously 285 284 * created with a call to another securityfs function (like 286 285 * securityfs_create_file() or variants thereof.) 287 286 * 288 287 * This function is required to be called in order for the file to be 289 - * removed, no automatic cleanup of files will happen when a module is 290 - * removed, you are responsible here. 288 + * removed. No automatic cleanup of files will happen when a module is 289 + * removed; you are responsible here. 291 290 */ 292 291 void securityfs_remove(struct dentry *dentry) 293 292 {
+4 -4
security/security.c
··· 82 82 * 83 83 * Return true if: 84 84 * -The passed LSM is the one chosen by user at boot time, 85 - * -or user didsn't specify a specific LSM and we're the first to ask 86 - * for registeration permissoin, 85 + * -or user didn't specify a specific LSM and we're the first to ask 86 + * for registration permission, 87 87 * -or the passed LSM is currently loaded. 88 88 * Otherwise, return false. 89 89 */ ··· 101 101 * register_security - registers a security framework with the kernel 102 102 * @ops: a pointer to the struct security_options that is to be registered 103 103 * 104 - * This function is to allow a security module to register itself with the 104 + * This function allows a security module to register itself with the 105 105 * kernel security subsystem. Some rudimentary checking is done on the @ops 106 106 * value passed to this function. You'll need to check first if your LSM 107 107 * is allowed to register its @ops by calling security_module_enable(@ops). 108 108 * 109 109 * If there is already a security module registered with the kernel, 110 - * an error will be returned. Otherwise 0 is returned on success. 110 + * an error will be returned. Otherwise %0 is returned on success. 111 111 */ 112 112 int register_security(struct security_operations *ops) 113 113 {
-3
security/selinux/Kconfig
··· 6 6 help 7 7 This selects NSA Security-Enhanced Linux (SELinux). 8 8 You will also need a policy configuration and a labeled filesystem. 9 - You can obtain the policy compiler (checkpolicy), the utility for 10 - labeling filesystems (setfiles), and an example policy configuration 11 - from <http://www.nsa.gov/selinux/>. 12 9 If you are unsure how to answer this question, answer N. 13 10 14 11 config SECURITY_SELINUX_BOOTPARAM
+1 -1
security/selinux/avc.c
··· 136 136 * @tclass: target security class 137 137 * @av: access vector 138 138 */ 139 - static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) 139 + void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) 140 140 { 141 141 const char **common_pts = NULL; 142 142 u32 common_base = 0;
+39 -23
security/selinux/hooks.c
··· 957 957 return rc; 958 958 } 959 959 960 - void selinux_write_opts(struct seq_file *m, struct security_mnt_opts *opts) 960 + static void selinux_write_opts(struct seq_file *m, 961 + struct security_mnt_opts *opts) 961 962 { 962 963 int i; 963 964 char *prefix; ··· 1291 1290 /* Default to the fs superblock SID. */ 1292 1291 isec->sid = sbsec->sid; 1293 1292 1294 - if (sbsec->proc) { 1293 + if (sbsec->proc && !S_ISLNK(inode->i_mode)) { 1295 1294 struct proc_inode *proci = PROC_I(inode); 1296 1295 if (proci->pde) { 1297 1296 isec->sclass = inode_mode_to_security_class(inode->i_mode); ··· 3549 3548 #endif /* IPV6 */ 3550 3549 3551 3550 static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, 3552 - char **addrp, int src, u8 *proto) 3551 + char **_addrp, int src, u8 *proto) 3553 3552 { 3554 - int ret = 0; 3553 + char *addrp; 3554 + int ret; 3555 3555 3556 3556 switch (ad->u.net.family) { 3557 3557 case PF_INET: 3558 3558 ret = selinux_parse_skb_ipv4(skb, ad, proto); 3559 - if (ret || !addrp) 3560 - break; 3561 - *addrp = (char *)(src ? &ad->u.net.v4info.saddr : 3562 - &ad->u.net.v4info.daddr); 3563 - break; 3559 + if (ret) 3560 + goto parse_error; 3561 + addrp = (char *)(src ? &ad->u.net.v4info.saddr : 3562 + &ad->u.net.v4info.daddr); 3563 + goto okay; 3564 3564 3565 3565 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 3566 3566 case PF_INET6: 3567 3567 ret = selinux_parse_skb_ipv6(skb, ad, proto); 3568 - if (ret || !addrp) 3569 - break; 3570 - *addrp = (char *)(src ? &ad->u.net.v6info.saddr : 3571 - &ad->u.net.v6info.daddr); 3572 - break; 3568 + if (ret) 3569 + goto parse_error; 3570 + addrp = (char *)(src ? &ad->u.net.v6info.saddr : 3571 + &ad->u.net.v6info.daddr); 3572 + goto okay; 3573 3573 #endif /* IPV6 */ 3574 3574 default: 3575 - break; 3575 + addrp = NULL; 3576 + goto okay; 3576 3577 } 3577 3578 3578 - if (unlikely(ret)) 3579 - printk(KERN_WARNING 3580 - "SELinux: failure in selinux_parse_skb()," 3581 - " unable to parse packet\n"); 3582 - 3579 + parse_error: 3580 + printk(KERN_WARNING 3581 + "SELinux: failure in selinux_parse_skb()," 3582 + " unable to parse packet\n"); 3583 3583 return ret; 3584 + 3585 + okay: 3586 + if (_addrp) 3587 + *_addrp = addrp; 3588 + return 0; 3584 3589 } 3585 3590 3586 3591 /** ··· 5226 5219 5227 5220 if (sid == 0) 5228 5221 return -EINVAL; 5229 - 5230 - /* Only allow single threaded processes to change context */ 5222 + /* 5223 + * SELinux allows to change context in the following case only. 5224 + * - Single threaded processes. 5225 + * - Multi threaded processes intend to change its context into 5226 + * more restricted domain (defined by TYPEBOUNDS statement). 5227 + */ 5231 5228 if (atomic_read(&p->mm->mm_users) != 1) { 5232 5229 struct task_struct *g, *t; 5233 5230 struct mm_struct *mm = p->mm; ··· 5239 5228 do_each_thread(g, t) { 5240 5229 if (t->mm == mm && t != p) { 5241 5230 read_unlock(&tasklist_lock); 5242 - return -EPERM; 5231 + error = security_bounded_transition(tsec->sid, sid); 5232 + if (!error) 5233 + goto boundary_ok; 5234 + 5235 + return error; 5243 5236 } 5244 5237 } while_each_thread(g, t); 5245 5238 read_unlock(&tasklist_lock); 5246 5239 } 5240 + boundary_ok: 5247 5241 5248 5242 /* Check permissions for the transition. */ 5249 5243 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
+4
security/selinux/include/avc.h
··· 12 12 #include <linux/kdev_t.h> 13 13 #include <linux/spinlock.h> 14 14 #include <linux/init.h> 15 + #include <linux/audit.h> 15 16 #include <linux/in6.h> 16 17 #include <linux/path.h> 17 18 #include <asm/system.h> ··· 126 125 u32 *out_retained), 127 126 u32 events, u32 ssid, u32 tsid, 128 127 u16 tclass, u32 perms); 128 + 129 + /* Shows permission in human readable form */ 130 + void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av); 129 131 130 132 /* Exported to selinuxfs */ 131 133 int avc_get_hash_stats(char *page);
+14 -1
security/selinux/include/security.h
··· 27 27 #define POLICYDB_VERSION_RANGETRANS 21 28 28 #define POLICYDB_VERSION_POLCAP 22 29 29 #define POLICYDB_VERSION_PERMISSIVE 23 30 + #define POLICYDB_VERSION_BOUNDARY 24 30 31 31 32 /* Range of policy versions we understand*/ 32 33 #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE 33 34 #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX 34 35 #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE 35 36 #else 36 - #define POLICYDB_VERSION_MAX POLICYDB_VERSION_PERMISSIVE 37 + #define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY 37 38 #endif 38 39 39 40 #define CONTEXT_MNT 0x01 ··· 62 61 63 62 extern int selinux_policycap_netpeer; 64 63 extern int selinux_policycap_openperm; 64 + 65 + /* 66 + * type_datum properties 67 + * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY 68 + */ 69 + #define TYPEDATUM_PROPERTY_PRIMARY 0x0001 70 + #define TYPEDATUM_PROPERTY_ATTRIBUTE 0x0002 71 + 72 + /* limitation of boundary depth */ 73 + #define POLICYDB_BOUNDS_MAXDEPTH 4 65 74 66 75 int security_load_policy(void *data, size_t len); 67 76 ··· 127 116 128 117 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, 129 118 u16 tclass); 119 + 120 + int security_bounded_transition(u32 oldsid, u32 newsid); 130 121 131 122 int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); 132 123
+3 -5
security/selinux/ss/avtab.c
··· 98 98 avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum) 99 99 { 100 100 int hvalue; 101 - struct avtab_node *prev, *cur, *newnode; 101 + struct avtab_node *prev, *cur; 102 102 u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); 103 103 104 104 if (!h || !h->htable) ··· 122 122 key->target_class < cur->key.target_class) 123 123 break; 124 124 } 125 - newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum); 126 - 127 - return newnode; 125 + return avtab_insert_node(h, hvalue, prev, cur, key, datum); 128 126 } 129 127 130 128 struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key) ··· 229 231 230 232 for (i = 0; i < h->nslot; i++) { 231 233 cur = h->htable[i]; 232 - while (cur != NULL) { 234 + while (cur) { 233 235 temp = cur; 234 236 cur = cur->next; 235 237 kmem_cache_free(avtab_node_cachep, temp);
+9 -9
security/selinux/ss/conditional.c
··· 29 29 int s[COND_EXPR_MAXDEPTH]; 30 30 int sp = -1; 31 31 32 - for (cur = expr; cur != NULL; cur = cur->next) { 32 + for (cur = expr; cur; cur = cur->next) { 33 33 switch (cur->expr_type) { 34 34 case COND_BOOL: 35 35 if (sp == (COND_EXPR_MAXDEPTH - 1)) ··· 97 97 if (new_state == -1) 98 98 printk(KERN_ERR "SELinux: expression result was undefined - disabling all rules.\n"); 99 99 /* turn the rules on or off */ 100 - for (cur = node->true_list; cur != NULL; cur = cur->next) { 100 + for (cur = node->true_list; cur; cur = cur->next) { 101 101 if (new_state <= 0) 102 102 cur->node->key.specified &= ~AVTAB_ENABLED; 103 103 else 104 104 cur->node->key.specified |= AVTAB_ENABLED; 105 105 } 106 106 107 - for (cur = node->false_list; cur != NULL; cur = cur->next) { 107 + for (cur = node->false_list; cur; cur = cur->next) { 108 108 /* -1 or 1 */ 109 109 if (new_state) 110 110 cur->node->key.specified &= ~AVTAB_ENABLED; ··· 128 128 static void cond_av_list_destroy(struct cond_av_list *list) 129 129 { 130 130 struct cond_av_list *cur, *next; 131 - for (cur = list; cur != NULL; cur = next) { 131 + for (cur = list; cur; cur = next) { 132 132 next = cur->next; 133 133 /* the avtab_ptr_t node is destroy by the avtab */ 134 134 kfree(cur); ··· 139 139 { 140 140 struct cond_expr *cur_expr, *next_expr; 141 141 142 - for (cur_expr = node->expr; cur_expr != NULL; cur_expr = next_expr) { 142 + for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) { 143 143 next_expr = cur_expr->next; 144 144 kfree(cur_expr); 145 145 } ··· 155 155 if (list == NULL) 156 156 return; 157 157 158 - for (cur = list; cur != NULL; cur = next) { 158 + for (cur = list; cur; cur = next) { 159 159 next = cur->next; 160 160 cond_node_destroy(cur); 161 161 } ··· 239 239 rc = next_entry(key, fp, len); 240 240 if (rc < 0) 241 241 goto err; 242 - key[len] = 0; 242 + key[len] = '\0'; 243 243 if (hashtab_insert(h, key, booldatum)) 244 244 goto err; 245 245 ··· 291 291 goto err; 292 292 } 293 293 found = 0; 294 - for (cur = other; cur != NULL; cur = cur->next) { 294 + for (cur = other; cur; cur = cur->next) { 295 295 if (cur->node == node_ptr) { 296 296 found = 1; 297 297 break; ··· 485 485 if (!ctab || !key || !avd) 486 486 return; 487 487 488 - for (node = avtab_search_node(ctab, key); node != NULL; 488 + for (node = avtab_search_node(ctab, key); node; 489 489 node = avtab_search_node_next(node, key->specified)) { 490 490 if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == 491 491 (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
+1 -1
security/selinux/ss/conditional.h
··· 28 28 #define COND_XOR 5 /* bool ^ bool */ 29 29 #define COND_EQ 6 /* bool == bool */ 30 30 #define COND_NEQ 7 /* bool != bool */ 31 - #define COND_LAST 8 31 + #define COND_LAST COND_NEQ 32 32 __u32 expr_type; 33 33 __u32 bool; 34 34 struct cond_expr *next;
+2 -2
security/selinux/ss/ebitmap.c
··· 109 109 *catmap = c_iter; 110 110 c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1); 111 111 112 - while (e_iter != NULL) { 112 + while (e_iter) { 113 113 for (i = 0; i < EBITMAP_UNIT_NUMS; i++) { 114 114 unsigned int delta, e_startbit, c_endbit; 115 115 ··· 197 197 } 198 198 } 199 199 c_iter = c_iter->next; 200 - } while (c_iter != NULL); 200 + } while (c_iter); 201 201 if (e_iter != NULL) 202 202 ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; 203 203 else
+3 -3
security/selinux/ss/hashtab.c
··· 81 81 82 82 hvalue = h->hash_value(h, key); 83 83 cur = h->htable[hvalue]; 84 - while (cur != NULL && h->keycmp(h, key, cur->key) > 0) 84 + while (cur && h->keycmp(h, key, cur->key) > 0) 85 85 cur = cur->next; 86 86 87 87 if (cur == NULL || (h->keycmp(h, key, cur->key) != 0)) ··· 100 100 101 101 for (i = 0; i < h->size; i++) { 102 102 cur = h->htable[i]; 103 - while (cur != NULL) { 103 + while (cur) { 104 104 temp = cur; 105 105 cur = cur->next; 106 106 kfree(temp); ··· 127 127 128 128 for (i = 0; i < h->size; i++) { 129 129 cur = h->htable[i]; 130 - while (cur != NULL) { 130 + while (cur) { 131 131 ret = apply(cur->key, cur->datum, args); 132 132 if (ret) 133 133 return ret;
+7 -7
security/selinux/ss/mls.c
··· 283 283 p++; 284 284 285 285 delim = *p; 286 - if (delim != 0) 287 - *p++ = 0; 286 + if (delim != '\0') 287 + *p++ = '\0'; 288 288 289 289 for (l = 0; l < 2; l++) { 290 290 levdatum = hashtab_search(pol->p_levels.table, scontextp); ··· 302 302 while (*p && *p != ',' && *p != '-') 303 303 p++; 304 304 delim = *p; 305 - if (delim != 0) 306 - *p++ = 0; 305 + if (delim != '\0') 306 + *p++ = '\0'; 307 307 308 308 /* Separate into range if exists */ 309 309 rngptr = strchr(scontextp, '.'); 310 310 if (rngptr != NULL) { 311 311 /* Remove '.' */ 312 - *rngptr++ = 0; 312 + *rngptr++ = '\0'; 313 313 } 314 314 315 315 catdatum = hashtab_search(pol->p_cats.table, ··· 357 357 p++; 358 358 359 359 delim = *p; 360 - if (delim != 0) 361 - *p++ = 0; 360 + if (delim != '\0') 361 + *p++ = '\0'; 362 362 } else 363 363 break; 364 364 }
+201 -24
security/selinux/ss/policydb.c
··· 30 30 #include <linux/slab.h> 31 31 #include <linux/string.h> 32 32 #include <linux/errno.h> 33 + #include <linux/audit.h> 33 34 #include "security.h" 34 35 35 36 #include "policydb.h" ··· 117 116 .version = POLICYDB_VERSION_PERMISSIVE, 118 117 .sym_num = SYM_NUM, 119 118 .ocon_num = OCON_NUM, 120 - } 119 + }, 120 + { 121 + .version = POLICYDB_VERSION_BOUNDARY, 122 + .sym_num = SYM_NUM, 123 + .ocon_num = OCON_NUM, 124 + }, 121 125 }; 122 126 123 127 static struct policydb_compat_info *policydb_lookup_compat(int version) ··· 260 254 261 255 role = datum; 262 256 p = datap; 263 - if (!role->value || role->value > p->p_roles.nprim) 257 + if (!role->value 258 + || role->value > p->p_roles.nprim 259 + || role->bounds > p->p_roles.nprim) 264 260 return -EINVAL; 265 261 p->p_role_val_to_name[role->value - 1] = key; 266 262 p->role_val_to_struct[role->value - 1] = role; ··· 278 270 p = datap; 279 271 280 272 if (typdatum->primary) { 281 - if (!typdatum->value || typdatum->value > p->p_types.nprim) 273 + if (!typdatum->value 274 + || typdatum->value > p->p_types.nprim 275 + || typdatum->bounds > p->p_types.nprim) 282 276 return -EINVAL; 283 277 p->p_type_val_to_name[typdatum->value - 1] = key; 278 + p->type_val_to_struct[typdatum->value - 1] = typdatum; 284 279 } 285 280 286 281 return 0; ··· 296 285 297 286 usrdatum = datum; 298 287 p = datap; 299 - if (!usrdatum->value || usrdatum->value > p->p_users.nprim) 288 + if (!usrdatum->value 289 + || usrdatum->value > p->p_users.nprim 290 + || usrdatum->bounds > p->p_users.nprim) 300 291 return -EINVAL; 301 292 p->p_user_val_to_name[usrdatum->value - 1] = key; 302 293 p->user_val_to_struct[usrdatum->value - 1] = usrdatum; ··· 447 434 kmalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)), 448 435 GFP_KERNEL); 449 436 if (!p->user_val_to_struct) { 437 + rc = -ENOMEM; 438 + goto out; 439 + } 440 + 441 + p->type_val_to_struct = 442 + kmalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)), 443 + GFP_KERNEL); 444 + if (!p->type_val_to_struct) { 450 445 rc = -ENOMEM; 451 446 goto out; 452 447 } ··· 646 625 kfree(p->class_val_to_struct); 647 626 kfree(p->role_val_to_struct); 648 627 kfree(p->user_val_to_struct); 628 + kfree(p->type_val_to_struct); 649 629 650 630 avtab_destroy(&p->te_avtab); 651 631 ··· 954 932 rc = next_entry(key, fp, len); 955 933 if (rc < 0) 956 934 goto bad; 957 - key[len] = 0; 935 + key[len] = '\0'; 958 936 959 937 rc = hashtab_insert(h, key, perdatum); 960 938 if (rc) ··· 1001 979 rc = next_entry(key, fp, len); 1002 980 if (rc < 0) 1003 981 goto bad; 1004 - key[len] = 0; 982 + key[len] = '\0'; 1005 983 1006 984 for (i = 0; i < nel; i++) { 1007 985 rc = perm_read(p, comdatum->permissions.table, fp); ··· 1139 1117 rc = next_entry(key, fp, len); 1140 1118 if (rc < 0) 1141 1119 goto bad; 1142 - key[len] = 0; 1120 + key[len] = '\0'; 1143 1121 1144 1122 if (len2) { 1145 1123 cladatum->comkey = kmalloc(len2 + 1, GFP_KERNEL); ··· 1150 1128 rc = next_entry(cladatum->comkey, fp, len2); 1151 1129 if (rc < 0) 1152 1130 goto bad; 1153 - cladatum->comkey[len2] = 0; 1131 + cladatum->comkey[len2] = '\0'; 1154 1132 1155 1133 cladatum->comdatum = hashtab_search(p->p_commons.table, 1156 1134 cladatum->comkey); ··· 1198 1176 { 1199 1177 char *key = NULL; 1200 1178 struct role_datum *role; 1201 - int rc; 1202 - __le32 buf[2]; 1179 + int rc, to_read = 2; 1180 + __le32 buf[3]; 1203 1181 u32 len; 1204 1182 1205 1183 role = kzalloc(sizeof(*role), GFP_KERNEL); ··· 1208 1186 goto out; 1209 1187 } 1210 1188 1211 - rc = next_entry(buf, fp, sizeof buf); 1189 + if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) 1190 + to_read = 3; 1191 + 1192 + rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); 1212 1193 if (rc < 0) 1213 1194 goto bad; 1214 1195 1215 1196 len = le32_to_cpu(buf[0]); 1216 1197 role->value = le32_to_cpu(buf[1]); 1198 + if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) 1199 + role->bounds = le32_to_cpu(buf[2]); 1217 1200 1218 1201 key = kmalloc(len + 1, GFP_KERNEL); 1219 1202 if (!key) { ··· 1228 1201 rc = next_entry(key, fp, len); 1229 1202 if (rc < 0) 1230 1203 goto bad; 1231 - key[len] = 0; 1204 + key[len] = '\0'; 1232 1205 1233 1206 rc = ebitmap_read(&role->dominates, fp); 1234 1207 if (rc) ··· 1263 1236 { 1264 1237 char *key = NULL; 1265 1238 struct type_datum *typdatum; 1266 - int rc; 1267 - __le32 buf[3]; 1239 + int rc, to_read = 3; 1240 + __le32 buf[4]; 1268 1241 u32 len; 1269 1242 1270 1243 typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL); ··· 1273 1246 return rc; 1274 1247 } 1275 1248 1276 - rc = next_entry(buf, fp, sizeof buf); 1249 + if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) 1250 + to_read = 4; 1251 + 1252 + rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); 1277 1253 if (rc < 0) 1278 1254 goto bad; 1279 1255 1280 1256 len = le32_to_cpu(buf[0]); 1281 1257 typdatum->value = le32_to_cpu(buf[1]); 1282 - typdatum->primary = le32_to_cpu(buf[2]); 1258 + if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) { 1259 + u32 prop = le32_to_cpu(buf[2]); 1260 + 1261 + if (prop & TYPEDATUM_PROPERTY_PRIMARY) 1262 + typdatum->primary = 1; 1263 + if (prop & TYPEDATUM_PROPERTY_ATTRIBUTE) 1264 + typdatum->attribute = 1; 1265 + 1266 + typdatum->bounds = le32_to_cpu(buf[3]); 1267 + } else { 1268 + typdatum->primary = le32_to_cpu(buf[2]); 1269 + } 1283 1270 1284 1271 key = kmalloc(len + 1, GFP_KERNEL); 1285 1272 if (!key) { ··· 1303 1262 rc = next_entry(key, fp, len); 1304 1263 if (rc < 0) 1305 1264 goto bad; 1306 - key[len] = 0; 1265 + key[len] = '\0'; 1307 1266 1308 1267 rc = hashtab_insert(h, key, typdatum); 1309 1268 if (rc) ··· 1350 1309 { 1351 1310 char *key = NULL; 1352 1311 struct user_datum *usrdatum; 1353 - int rc; 1354 - __le32 buf[2]; 1312 + int rc, to_read = 2; 1313 + __le32 buf[3]; 1355 1314 u32 len; 1356 1315 1357 1316 usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL); ··· 1360 1319 goto out; 1361 1320 } 1362 1321 1363 - rc = next_entry(buf, fp, sizeof buf); 1322 + if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) 1323 + to_read = 3; 1324 + 1325 + rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); 1364 1326 if (rc < 0) 1365 1327 goto bad; 1366 1328 1367 1329 len = le32_to_cpu(buf[0]); 1368 1330 usrdatum->value = le32_to_cpu(buf[1]); 1331 + if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) 1332 + usrdatum->bounds = le32_to_cpu(buf[2]); 1369 1333 1370 1334 key = kmalloc(len + 1, GFP_KERNEL); 1371 1335 if (!key) { ··· 1380 1334 rc = next_entry(key, fp, len); 1381 1335 if (rc < 0) 1382 1336 goto bad; 1383 - key[len] = 0; 1337 + key[len] = '\0'; 1384 1338 1385 1339 rc = ebitmap_read(&usrdatum->roles, fp); 1386 1340 if (rc) ··· 1434 1388 rc = next_entry(key, fp, len); 1435 1389 if (rc < 0) 1436 1390 goto bad; 1437 - key[len] = 0; 1391 + key[len] = '\0'; 1438 1392 1439 1393 levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); 1440 1394 if (!levdatum->level) { ··· 1486 1440 rc = next_entry(key, fp, len); 1487 1441 if (rc < 0) 1488 1442 goto bad; 1489 - key[len] = 0; 1443 + key[len] = '\0'; 1490 1444 1491 1445 rc = hashtab_insert(h, key, catdatum); 1492 1446 if (rc) ··· 1510 1464 sens_read, 1511 1465 cat_read, 1512 1466 }; 1467 + 1468 + static int user_bounds_sanity_check(void *key, void *datum, void *datap) 1469 + { 1470 + struct user_datum *upper, *user; 1471 + struct policydb *p = datap; 1472 + int depth = 0; 1473 + 1474 + upper = user = datum; 1475 + while (upper->bounds) { 1476 + struct ebitmap_node *node; 1477 + unsigned long bit; 1478 + 1479 + if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { 1480 + printk(KERN_ERR "SELinux: user %s: " 1481 + "too deep or looped boundary", 1482 + (char *) key); 1483 + return -EINVAL; 1484 + } 1485 + 1486 + upper = p->user_val_to_struct[upper->bounds - 1]; 1487 + ebitmap_for_each_positive_bit(&user->roles, node, bit) { 1488 + if (ebitmap_get_bit(&upper->roles, bit)) 1489 + continue; 1490 + 1491 + printk(KERN_ERR 1492 + "SELinux: boundary violated policy: " 1493 + "user=%s role=%s bounds=%s\n", 1494 + p->p_user_val_to_name[user->value - 1], 1495 + p->p_role_val_to_name[bit], 1496 + p->p_user_val_to_name[upper->value - 1]); 1497 + 1498 + return -EINVAL; 1499 + } 1500 + } 1501 + 1502 + return 0; 1503 + } 1504 + 1505 + static int role_bounds_sanity_check(void *key, void *datum, void *datap) 1506 + { 1507 + struct role_datum *upper, *role; 1508 + struct policydb *p = datap; 1509 + int depth = 0; 1510 + 1511 + upper = role = datum; 1512 + while (upper->bounds) { 1513 + struct ebitmap_node *node; 1514 + unsigned long bit; 1515 + 1516 + if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { 1517 + printk(KERN_ERR "SELinux: role %s: " 1518 + "too deep or looped bounds\n", 1519 + (char *) key); 1520 + return -EINVAL; 1521 + } 1522 + 1523 + upper = p->role_val_to_struct[upper->bounds - 1]; 1524 + ebitmap_for_each_positive_bit(&role->types, node, bit) { 1525 + if (ebitmap_get_bit(&upper->types, bit)) 1526 + continue; 1527 + 1528 + printk(KERN_ERR 1529 + "SELinux: boundary violated policy: " 1530 + "role=%s type=%s bounds=%s\n", 1531 + p->p_role_val_to_name[role->value - 1], 1532 + p->p_type_val_to_name[bit], 1533 + p->p_role_val_to_name[upper->value - 1]); 1534 + 1535 + return -EINVAL; 1536 + } 1537 + } 1538 + 1539 + return 0; 1540 + } 1541 + 1542 + static int type_bounds_sanity_check(void *key, void *datum, void *datap) 1543 + { 1544 + struct type_datum *upper, *type; 1545 + struct policydb *p = datap; 1546 + int depth = 0; 1547 + 1548 + upper = type = datum; 1549 + while (upper->bounds) { 1550 + if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { 1551 + printk(KERN_ERR "SELinux: type %s: " 1552 + "too deep or looped boundary\n", 1553 + (char *) key); 1554 + return -EINVAL; 1555 + } 1556 + 1557 + upper = p->type_val_to_struct[upper->bounds - 1]; 1558 + if (upper->attribute) { 1559 + printk(KERN_ERR "SELinux: type %s: " 1560 + "bounded by attribute %s", 1561 + (char *) key, 1562 + p->p_type_val_to_name[upper->value - 1]); 1563 + return -EINVAL; 1564 + } 1565 + } 1566 + 1567 + return 0; 1568 + } 1569 + 1570 + static int policydb_bounds_sanity_check(struct policydb *p) 1571 + { 1572 + int rc; 1573 + 1574 + if (p->policyvers < POLICYDB_VERSION_BOUNDARY) 1575 + return 0; 1576 + 1577 + rc = hashtab_map(p->p_users.table, 1578 + user_bounds_sanity_check, p); 1579 + if (rc) 1580 + return rc; 1581 + 1582 + rc = hashtab_map(p->p_roles.table, 1583 + role_bounds_sanity_check, p); 1584 + if (rc) 1585 + return rc; 1586 + 1587 + rc = hashtab_map(p->p_types.table, 1588 + type_bounds_sanity_check, p); 1589 + if (rc) 1590 + return rc; 1591 + 1592 + return 0; 1593 + } 1513 1594 1514 1595 extern int ss_initialized; 1515 1596 ··· 1696 1523 kfree(policydb_str); 1697 1524 goto bad; 1698 1525 } 1699 - policydb_str[len] = 0; 1526 + policydb_str[len] = '\0'; 1700 1527 if (strcmp(policydb_str, POLICYDB_STRING)) { 1701 1528 printk(KERN_ERR "SELinux: policydb string %s does not match " 1702 1529 "my string %s\n", policydb_str, POLICYDB_STRING); ··· 2133 1960 if (ebitmap_set_bit(&p->type_attr_map[i], i, 1)) 2134 1961 goto bad; 2135 1962 } 1963 + 1964 + rc = policydb_bounds_sanity_check(p); 1965 + if (rc) 1966 + goto bad; 2136 1967 2137 1968 rc = 0; 2138 1969 out:
+5
security/selinux/ss/policydb.h
··· 61 61 /* Role attributes */ 62 62 struct role_datum { 63 63 u32 value; /* internal role value */ 64 + u32 bounds; /* boundary of role */ 64 65 struct ebitmap dominates; /* set of roles dominated by this role */ 65 66 struct ebitmap types; /* set of authorized types for role */ 66 67 }; ··· 82 81 /* Type attributes */ 83 82 struct type_datum { 84 83 u32 value; /* internal type value */ 84 + u32 bounds; /* boundary of type */ 85 85 unsigned char primary; /* primary name? */ 86 + unsigned char attribute;/* attribute ?*/ 86 87 }; 87 88 88 89 /* User attributes */ 89 90 struct user_datum { 90 91 u32 value; /* internal user value */ 92 + u32 bounds; /* bounds of user */ 91 93 struct ebitmap roles; /* set of authorized roles for user */ 92 94 struct mls_range range; /* MLS range (min - max) for user */ 93 95 struct mls_level dfltlevel; /* default login MLS level for user */ ··· 213 209 struct class_datum **class_val_to_struct; 214 210 struct role_datum **role_val_to_struct; 215 211 struct user_datum **user_val_to_struct; 212 + struct type_datum **type_val_to_struct; 216 213 217 214 /* type enforcement access vectors and transitions */ 218 215 struct avtab te_avtab;
+175 -5
security/selinux/ss/services.c
··· 88 88 static int context_struct_to_string(struct context *context, char **scontext, 89 89 u32 *scontext_len); 90 90 91 + static int context_struct_compute_av(struct context *scontext, 92 + struct context *tcontext, 93 + u16 tclass, 94 + u32 requested, 95 + struct av_decision *avd); 91 96 /* 92 97 * Return the boolean value of a constraint expression 93 98 * when it is applied to the specified source and target ··· 279 274 } 280 275 281 276 /* 277 + * security_boundary_permission - drops violated permissions 278 + * on boundary constraint. 279 + */ 280 + static void type_attribute_bounds_av(struct context *scontext, 281 + struct context *tcontext, 282 + u16 tclass, 283 + u32 requested, 284 + struct av_decision *avd) 285 + { 286 + struct context lo_scontext; 287 + struct context lo_tcontext; 288 + struct av_decision lo_avd; 289 + struct type_datum *source 290 + = policydb.type_val_to_struct[scontext->type - 1]; 291 + struct type_datum *target 292 + = policydb.type_val_to_struct[tcontext->type - 1]; 293 + u32 masked = 0; 294 + 295 + if (source->bounds) { 296 + memset(&lo_avd, 0, sizeof(lo_avd)); 297 + 298 + memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); 299 + lo_scontext.type = source->bounds; 300 + 301 + context_struct_compute_av(&lo_scontext, 302 + tcontext, 303 + tclass, 304 + requested, 305 + &lo_avd); 306 + if ((lo_avd.allowed & avd->allowed) == avd->allowed) 307 + return; /* no masked permission */ 308 + masked = ~lo_avd.allowed & avd->allowed; 309 + } 310 + 311 + if (target->bounds) { 312 + memset(&lo_avd, 0, sizeof(lo_avd)); 313 + 314 + memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); 315 + lo_tcontext.type = target->bounds; 316 + 317 + context_struct_compute_av(scontext, 318 + &lo_tcontext, 319 + tclass, 320 + requested, 321 + &lo_avd); 322 + if ((lo_avd.allowed & avd->allowed) == avd->allowed) 323 + return; /* no masked permission */ 324 + masked = ~lo_avd.allowed & avd->allowed; 325 + } 326 + 327 + if (source->bounds && target->bounds) { 328 + memset(&lo_avd, 0, sizeof(lo_avd)); 329 + /* 330 + * lo_scontext and lo_tcontext are already 331 + * set up. 332 + */ 333 + 334 + context_struct_compute_av(&lo_scontext, 335 + &lo_tcontext, 336 + tclass, 337 + requested, 338 + &lo_avd); 339 + if ((lo_avd.allowed & avd->allowed) == avd->allowed) 340 + return; /* no masked permission */ 341 + masked = ~lo_avd.allowed & avd->allowed; 342 + } 343 + 344 + if (masked) { 345 + struct audit_buffer *ab; 346 + char *stype_name 347 + = policydb.p_type_val_to_name[source->value - 1]; 348 + char *ttype_name 349 + = policydb.p_type_val_to_name[target->value - 1]; 350 + char *tclass_name 351 + = policydb.p_class_val_to_name[tclass - 1]; 352 + 353 + /* mask violated permissions */ 354 + avd->allowed &= ~masked; 355 + 356 + /* notice to userspace via audit message */ 357 + ab = audit_log_start(current->audit_context, 358 + GFP_ATOMIC, AUDIT_SELINUX_ERR); 359 + if (!ab) 360 + return; 361 + 362 + audit_log_format(ab, "av boundary violation: " 363 + "source=%s target=%s tclass=%s", 364 + stype_name, ttype_name, tclass_name); 365 + avc_dump_av(ab, tclass, masked); 366 + audit_log_end(ab); 367 + } 368 + } 369 + 370 + /* 282 371 * Compute access vectors based on a context structure pair for 283 372 * the permissions in a particular class. 284 373 */ ··· 455 356 avkey.source_type = i + 1; 456 357 avkey.target_type = j + 1; 457 358 for (node = avtab_search_node(&policydb.te_avtab, &avkey); 458 - node != NULL; 359 + node; 459 360 node = avtab_search_node_next(node, avkey.specified)) { 460 361 if (node->key.specified == AVTAB_ALLOWED) 461 362 avd->allowed |= node->datum.data; ··· 502 403 avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION | 503 404 PROCESS__DYNTRANSITION); 504 405 } 406 + 407 + /* 408 + * If the given source and target types have boundary 409 + * constraint, lazy checks have to mask any violated 410 + * permission and notice it to userspace via audit. 411 + */ 412 + type_attribute_bounds_av(scontext, tcontext, 413 + tclass, requested, avd); 505 414 506 415 return 0; 507 416 ··· 655 548 read_unlock(&policy_rwlock); 656 549 return rc; 657 550 } 551 + 552 + /* 553 + * security_bounded_transition - check whether the given 554 + * transition is directed to bounded, or not. 555 + * It returns 0, if @newsid is bounded by @oldsid. 556 + * Otherwise, it returns error code. 557 + * 558 + * @oldsid : current security identifier 559 + * @newsid : destinated security identifier 560 + */ 561 + int security_bounded_transition(u32 old_sid, u32 new_sid) 562 + { 563 + struct context *old_context, *new_context; 564 + struct type_datum *type; 565 + int index; 566 + int rc = -EINVAL; 567 + 568 + read_lock(&policy_rwlock); 569 + 570 + old_context = sidtab_search(&sidtab, old_sid); 571 + if (!old_context) { 572 + printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", 573 + __func__, old_sid); 574 + goto out; 575 + } 576 + 577 + new_context = sidtab_search(&sidtab, new_sid); 578 + if (!new_context) { 579 + printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", 580 + __func__, new_sid); 581 + goto out; 582 + } 583 + 584 + /* type/domain unchaned */ 585 + if (old_context->type == new_context->type) { 586 + rc = 0; 587 + goto out; 588 + } 589 + 590 + index = new_context->type; 591 + while (true) { 592 + type = policydb.type_val_to_struct[index - 1]; 593 + BUG_ON(!type); 594 + 595 + /* not bounded anymore */ 596 + if (!type->bounds) { 597 + rc = -EPERM; 598 + break; 599 + } 600 + 601 + /* @newsid is bounded by @oldsid */ 602 + if (type->bounds == old_context->type) { 603 + rc = 0; 604 + break; 605 + } 606 + index = type->bounds; 607 + } 608 + out: 609 + read_unlock(&policy_rwlock); 610 + 611 + return rc; 612 + } 613 + 658 614 659 615 /** 660 616 * security_compute_av - Compute access vector decisions. ··· 964 794 *p++ = 0; 965 795 966 796 typdatum = hashtab_search(pol->p_types.table, scontextp); 967 - if (!typdatum) 797 + if (!typdatum || typdatum->attribute) 968 798 goto out; 969 799 970 800 ctx->type = typdatum->value; ··· 1207 1037 /* If no permanent rule, also check for enabled conditional rules */ 1208 1038 if (!avdatum) { 1209 1039 node = avtab_search_node(&policydb.te_cond_avtab, &avkey); 1210 - for (; node != NULL; node = avtab_search_node_next(node, specified)) { 1040 + for (; node; node = avtab_search_node_next(node, specified)) { 1211 1041 if (node->key.specified & AVTAB_ENABLED) { 1212 1042 avdatum = &node->datum; 1213 1043 break; ··· 2220 2050 policydb.bool_val_to_struct[i]->state = 0; 2221 2051 } 2222 2052 2223 - for (cur = policydb.cond_list; cur != NULL; cur = cur->next) { 2053 + for (cur = policydb.cond_list; cur; cur = cur->next) { 2224 2054 rc = evaluate_cond_node(&policydb, cur); 2225 2055 if (rc) 2226 2056 goto out; ··· 2272 2102 if (booldatum) 2273 2103 booldatum->state = bvalues[i]; 2274 2104 } 2275 - for (cur = p->cond_list; cur != NULL; cur = cur->next) { 2105 + for (cur = p->cond_list; cur; cur = cur->next) { 2276 2106 rc = evaluate_cond_node(p, cur); 2277 2107 if (rc) 2278 2108 goto out;
+6 -6
security/selinux/ss/sidtab.c
··· 43 43 hvalue = SIDTAB_HASH(sid); 44 44 prev = NULL; 45 45 cur = s->htable[hvalue]; 46 - while (cur != NULL && sid > cur->sid) { 46 + while (cur && sid > cur->sid) { 47 47 prev = cur; 48 48 cur = cur->next; 49 49 } ··· 92 92 93 93 hvalue = SIDTAB_HASH(sid); 94 94 cur = s->htable[hvalue]; 95 - while (cur != NULL && sid > cur->sid) 95 + while (cur && sid > cur->sid) 96 96 cur = cur->next; 97 97 98 98 if (force && cur && sid == cur->sid && cur->context.len) ··· 103 103 sid = SECINITSID_UNLABELED; 104 104 hvalue = SIDTAB_HASH(sid); 105 105 cur = s->htable[hvalue]; 106 - while (cur != NULL && sid > cur->sid) 106 + while (cur && sid > cur->sid) 107 107 cur = cur->next; 108 108 if (!cur || sid != cur->sid) 109 109 return NULL; ··· 136 136 137 137 for (i = 0; i < SIDTAB_SIZE; i++) { 138 138 cur = s->htable[i]; 139 - while (cur != NULL) { 139 + while (cur) { 140 140 rc = apply(cur->sid, &cur->context, args); 141 141 if (rc) 142 142 goto out; ··· 155 155 156 156 for (i = 0; i < SIDTAB_SIZE; i++) { 157 157 cur = s->htable[i]; 158 - while (cur != NULL) { 158 + while (cur) { 159 159 if (context_cmp(&cur->context, context)) 160 160 return cur->sid; 161 161 cur = cur->next; ··· 242 242 243 243 for (i = 0; i < SIDTAB_SIZE; i++) { 244 244 cur = s->htable[i]; 245 - while (cur != NULL) { 245 + while (cur) { 246 246 temp = cur; 247 247 cur = cur->next; 248 248 context_destroy(&temp->context);
+1
security/smack/smack.h
··· 178 178 extern int smack_cipso_direct; 179 179 extern int smack_net_nltype; 180 180 extern char *smack_net_ambient; 181 + extern char *smack_onlycap; 181 182 182 183 extern struct smack_known *smack_known; 183 184 extern struct smack_known smack_known_floor;
+9 -1
security/smack/smack_access.c
··· 157 157 * 158 158 * This function checks the current subject label/object label pair 159 159 * in the access rule list and returns 0 if the access is permitted, 160 - * non zero otherwise. It allows that current my have the capability 160 + * non zero otherwise. It allows that current may have the capability 161 161 * to override the rules. 162 162 */ 163 163 int smk_curacc(char *obj_label, u32 mode) ··· 167 167 rc = smk_access(current->security, obj_label, mode); 168 168 if (rc == 0) 169 169 return 0; 170 + 171 + /* 172 + * Return if a specific label has been designated as the 173 + * only one that gets privilege and current does not 174 + * have that label. 175 + */ 176 + if (smack_onlycap != NULL && smack_onlycap != current->security) 177 + return rc; 170 178 171 179 if (capable(CAP_MAC_OVERRIDE)) 172 180 return 0;
+92
security/smack/smackfs.c
··· 39 39 SMK_DIRECT = 6, /* CIPSO level indicating direct label */ 40 40 SMK_AMBIENT = 7, /* internet ambient label */ 41 41 SMK_NLTYPE = 8, /* label scheme to use by default */ 42 + SMK_ONLYCAP = 9, /* the only "capable" label */ 42 43 }; 43 44 44 45 /* ··· 68 67 * It can be reset via smackfs/direct 69 68 */ 70 69 int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; 70 + 71 + /* 72 + * Unless a process is running with this label even 73 + * having CAP_MAC_OVERRIDE isn't enough to grant 74 + * privilege to violate MAC policy. If no label is 75 + * designated (the NULL case) capabilities apply to 76 + * everyone. It is expected that the hat (^) label 77 + * will be used if any label is used. 78 + */ 79 + char *smack_onlycap; 71 80 72 81 static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; 73 82 struct smk_list_entry *smack_list; ··· 798 787 .write = smk_write_ambient, 799 788 }; 800 789 790 + /** 791 + * smk_read_onlycap - read() for /smack/onlycap 792 + * @filp: file pointer, not actually used 793 + * @buf: where to put the result 794 + * @cn: maximum to send along 795 + * @ppos: where to start 796 + * 797 + * Returns number of bytes read or error code, as appropriate 798 + */ 799 + static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, 800 + size_t cn, loff_t *ppos) 801 + { 802 + char *smack = ""; 803 + ssize_t rc = -EINVAL; 804 + int asize; 805 + 806 + if (*ppos != 0) 807 + return 0; 808 + 809 + if (smack_onlycap != NULL) 810 + smack = smack_onlycap; 811 + 812 + asize = strlen(smack) + 1; 813 + 814 + if (cn >= asize) 815 + rc = simple_read_from_buffer(buf, cn, ppos, smack, asize); 816 + 817 + return rc; 818 + } 819 + 820 + /** 821 + * smk_write_onlycap - write() for /smack/onlycap 822 + * @filp: file pointer, not actually used 823 + * @buf: where to get the data from 824 + * @count: bytes sent 825 + * @ppos: where to start 826 + * 827 + * Returns number of bytes written or error code, as appropriate 828 + */ 829 + static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, 830 + size_t count, loff_t *ppos) 831 + { 832 + char in[SMK_LABELLEN]; 833 + char *sp = current->security; 834 + 835 + if (!capable(CAP_MAC_ADMIN)) 836 + return -EPERM; 837 + 838 + /* 839 + * This can be done using smk_access() but is done 840 + * explicitly for clarity. The smk_access() implementation 841 + * would use smk_access(smack_onlycap, MAY_WRITE) 842 + */ 843 + if (smack_onlycap != NULL && smack_onlycap != sp) 844 + return -EPERM; 845 + 846 + if (count >= SMK_LABELLEN) 847 + return -EINVAL; 848 + 849 + if (copy_from_user(in, buf, count) != 0) 850 + return -EFAULT; 851 + 852 + /* 853 + * Should the null string be passed in unset the onlycap value. 854 + * This seems like something to be careful with as usually 855 + * smk_import only expects to return NULL for errors. It 856 + * is usually the case that a nullstring or "\n" would be 857 + * bad to pass to smk_import but in fact this is useful here. 858 + */ 859 + smack_onlycap = smk_import(in, count); 860 + 861 + return count; 862 + } 863 + 864 + static const struct file_operations smk_onlycap_ops = { 865 + .read = smk_read_onlycap, 866 + .write = smk_write_onlycap, 867 + }; 868 + 801 869 struct option_names { 802 870 int o_number; 803 871 char *o_name; ··· 1009 919 {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, 1010 920 [SMK_NLTYPE] = 1011 921 {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR}, 922 + [SMK_ONLYCAP] = 923 + {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, 1012 924 /* last one */ {""} 1013 925 }; 1014 926