diff options
-rw-r--r-- | Documentation/security/Smack.txt | 204 | ||||
-rw-r--r-- | security/smack/smack.h | 57 | ||||
-rw-r--r-- | security/smack/smack_access.c | 233 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 237 | ||||
-rw-r--r-- | security/smack/smackfs.c | 993 |
5 files changed, 1145 insertions, 579 deletions
diff --git a/Documentation/security/Smack.txt b/Documentation/security/Smack.txt index d2f72ae66432..a416479b8a1c 100644 --- a/Documentation/security/Smack.txt +++ b/Documentation/security/Smack.txt | |||
@@ -15,7 +15,7 @@ at hand. | |||
15 | 15 | ||
16 | Smack consists of three major components: | 16 | Smack consists of three major components: |
17 | - The kernel | 17 | - The kernel |
18 | - A start-up script and a few modified applications | 18 | - Basic utilities, which are helpful but not required |
19 | - Configuration data | 19 | - Configuration data |
20 | 20 | ||
21 | The kernel component of Smack is implemented as a Linux | 21 | The kernel component of Smack is implemented as a Linux |
@@ -23,37 +23,28 @@ Security Modules (LSM) module. It requires netlabel and | |||
23 | works best with file systems that support extended attributes, | 23 | works best with file systems that support extended attributes, |
24 | although xattr support is not strictly required. | 24 | although xattr support is not strictly required. |
25 | It is safe to run a Smack kernel under a "vanilla" distribution. | 25 | It is safe to run a Smack kernel under a "vanilla" distribution. |
26 | |||
26 | Smack kernels use the CIPSO IP option. Some network | 27 | Smack kernels use the CIPSO IP option. Some network |
27 | configurations are intolerant of IP options and can impede | 28 | configurations are intolerant of IP options and can impede |
28 | access to systems that use them as Smack does. | 29 | access to systems that use them as Smack does. |
29 | 30 | ||
30 | The startup script etc-init.d-smack should be installed | 31 | The current git repositories for Smack user space are: |
31 | in /etc/init.d/smack and should be invoked early in the | ||
32 | start-up process. On Fedora rc5.d/S02smack is recommended. | ||
33 | This script ensures that certain devices have the correct | ||
34 | Smack attributes and loads the Smack configuration if | ||
35 | any is defined. This script invokes two programs that | ||
36 | ensure configuration data is properly formatted. These | ||
37 | programs are /usr/sbin/smackload and /usr/sin/smackcipso. | ||
38 | The system will run just fine without these programs, | ||
39 | but it will be difficult to set access rules properly. | ||
40 | |||
41 | A version of "ls" that provides a "-M" option to display | ||
42 | Smack labels on long listing is available. | ||
43 | 32 | ||
44 | A hacked version of sshd that allows network logins by users | 33 | git@gitorious.org:meego-platform-security/smackutil.git |
45 | with specific Smack labels is available. This version does | 34 | git@gitorious.org:meego-platform-security/libsmack.git |
46 | not work for scp. You must set the /etc/ssh/sshd_config | ||
47 | line: | ||
48 | UsePrivilegeSeparation no | ||
49 | 35 | ||
50 | The format of /etc/smack/usr is: | 36 | These should make and install on most modern distributions. |
37 | There are three commands included in smackutil: | ||
51 | 38 | ||
52 | username smack | 39 | smackload - properly formats data for writing to /smack/load |
40 | smackcipso - properly formats data for writing to /smack/cipso | ||
41 | chsmack - display or set Smack extended attribute values | ||
53 | 42 | ||
54 | In keeping with the intent of Smack, configuration data is | 43 | In keeping with the intent of Smack, configuration data is |
55 | minimal and not strictly required. The most important | 44 | minimal and not strictly required. The most important |
56 | configuration step is mounting the smackfs pseudo filesystem. | 45 | configuration step is mounting the smackfs pseudo filesystem. |
46 | If smackutil is installed the startup script will take care | ||
47 | of this, but it can be manually as well. | ||
57 | 48 | ||
58 | Add this line to /etc/fstab: | 49 | Add this line to /etc/fstab: |
59 | 50 | ||
@@ -61,19 +52,148 @@ Add this line to /etc/fstab: | |||
61 | 52 | ||
62 | and create the /smack directory for mounting. | 53 | and create the /smack directory for mounting. |
63 | 54 | ||
64 | Smack uses extended attributes (xattrs) to store file labels. | 55 | Smack uses extended attributes (xattrs) to store labels on filesystem |
65 | The command to set a Smack label on a file is: | 56 | objects. The attributes are stored in the extended attribute security |
57 | name space. A process must have CAP_MAC_ADMIN to change any of these | ||
58 | attributes. | ||
59 | |||
60 | The extended attributes that Smack uses are: | ||
61 | |||
62 | SMACK64 | ||
63 | Used to make access control decisions. In almost all cases | ||
64 | the label given to a new filesystem object will be the label | ||
65 | of the process that created it. | ||
66 | SMACK64EXEC | ||
67 | The Smack label of a process that execs a program file with | ||
68 | this attribute set will run with this attribute's value. | ||
69 | SMACK64MMAP | ||
70 | Don't allow the file to be mmapped by a process whose Smack | ||
71 | label does not allow all of the access permitted to a process | ||
72 | with the label contained in this attribute. This is a very | ||
73 | specific use case for shared libraries. | ||
74 | SMACK64TRANSMUTE | ||
75 | Can only have the value "TRUE". If this attribute is present | ||
76 | on a directory when an object is created in the directory and | ||
77 | the Smack rule (more below) that permitted the write access | ||
78 | to the directory includes the transmute ("t") mode the object | ||
79 | gets the label of the directory instead of the label of the | ||
80 | creating process. If the object being created is a directory | ||
81 | the SMACK64TRANSMUTE attribute is set as well. | ||
82 | SMACK64IPIN | ||
83 | This attribute is only available on file descriptors for sockets. | ||
84 | Use the Smack label in this attribute for access control | ||
85 | decisions on packets being delivered to this socket. | ||
86 | SMACK64IPOUT | ||
87 | This attribute is only available on file descriptors for sockets. | ||
88 | Use the Smack label in this attribute for access control | ||
89 | decisions on packets coming from this socket. | ||
90 | |||
91 | There are multiple ways to set a Smack label on a file: | ||
66 | 92 | ||
67 | # attr -S -s SMACK64 -V "value" path | 93 | # attr -S -s SMACK64 -V "value" path |
94 | # chsmack -a value path | ||
68 | 95 | ||
69 | NOTE: Smack labels are limited to 23 characters. The attr command | 96 | A process can see the smack label it is running with by |
70 | does not enforce this restriction and can be used to set | 97 | reading /proc/self/attr/current. A process with CAP_MAC_ADMIN |
71 | invalid Smack labels on files. | 98 | can set the process smack by writing there. |
72 | 99 | ||
73 | If you don't do anything special all users will get the floor ("_") | 100 | Most Smack configuration is accomplished by writing to files |
74 | label when they log in. If you do want to log in via the hacked ssh | 101 | in the smackfs filesystem. This pseudo-filesystem is usually |
75 | at other labels use the attr command to set the smack value on the | 102 | mounted on /smack. |
76 | home directory and its contents. | 103 | |
104 | access | ||
105 | This interface reports whether a subject with the specified | ||
106 | Smack label has a particular access to an object with a | ||
107 | specified Smack label. Write a fixed format access rule to | ||
108 | this file. The next read will indicate whether the access | ||
109 | would be permitted. The text will be either "1" indicating | ||
110 | access, or "0" indicating denial. | ||
111 | access2 | ||
112 | This interface reports whether a subject with the specified | ||
113 | Smack label has a particular access to an object with a | ||
114 | specified Smack label. Write a long format access rule to | ||
115 | this file. The next read will indicate whether the access | ||
116 | would be permitted. The text will be either "1" indicating | ||
117 | access, or "0" indicating denial. | ||
118 | ambient | ||
119 | This contains the Smack label applied to unlabeled network | ||
120 | packets. | ||
121 | cipso | ||
122 | This interface allows a specific CIPSO header to be assigned | ||
123 | to a Smack label. The format accepted on write is: | ||
124 | "%24s%4d%4d"["%4d"]... | ||
125 | The first string is a fixed Smack label. The first number is | ||
126 | the level to use. The second number is the number of categories. | ||
127 | The following numbers are the categories. | ||
128 | "level-3-cats-5-19 3 2 5 19" | ||
129 | cipso2 | ||
130 | This interface allows a specific CIPSO header to be assigned | ||
131 | to a Smack label. The format accepted on write is: | ||
132 | "%s%4d%4d"["%4d"]... | ||
133 | The first string is a long Smack label. The first number is | ||
134 | the level to use. The second number is the number of categories. | ||
135 | The following numbers are the categories. | ||
136 | "level-3-cats-5-19 3 2 5 19" | ||
137 | direct | ||
138 | This contains the CIPSO level used for Smack direct label | ||
139 | representation in network packets. | ||
140 | doi | ||
141 | This contains the CIPSO domain of interpretation used in | ||
142 | network packets. | ||
143 | load | ||
144 | This interface allows access control rules in addition to | ||
145 | the system defined rules to be specified. The format accepted | ||
146 | on write is: | ||
147 | "%24s%24s%5s" | ||
148 | where the first string is the subject label, the second the | ||
149 | object label, and the third the requested access. The access | ||
150 | string may contain only the characters "rwxat-", and specifies | ||
151 | which sort of access is allowed. The "-" is a placeholder for | ||
152 | permissions that are not allowed. The string "r-x--" would | ||
153 | specify read and execute access. Labels are limited to 23 | ||
154 | characters in length. | ||
155 | load2 | ||
156 | This interface allows access control rules in addition to | ||
157 | the system defined rules to be specified. The format accepted | ||
158 | on write is: | ||
159 | "%s %s %s" | ||
160 | where the first string is the subject label, the second the | ||
161 | object label, and the third the requested access. The access | ||
162 | string may contain only the characters "rwxat-", and specifies | ||
163 | which sort of access is allowed. The "-" is a placeholder for | ||
164 | permissions that are not allowed. The string "r-x--" would | ||
165 | specify read and execute access. | ||
166 | load-self | ||
167 | This interface allows process specific access rules to be | ||
168 | defined. These rules are only consulted if access would | ||
169 | otherwise be permitted, and are intended to provide additional | ||
170 | restrictions on the process. The format is the same as for | ||
171 | the load interface. | ||
172 | load-self2 | ||
173 | This interface allows process specific access rules to be | ||
174 | defined. These rules are only consulted if access would | ||
175 | otherwise be permitted, and are intended to provide additional | ||
176 | restrictions on the process. The format is the same as for | ||
177 | the load2 interface. | ||
178 | logging | ||
179 | This contains the Smack logging state. | ||
180 | mapped | ||
181 | This contains the CIPSO level used for Smack mapped label | ||
182 | representation in network packets. | ||
183 | netlabel | ||
184 | This interface allows specific internet addresses to be | ||
185 | treated as single label hosts. Packets are sent to single | ||
186 | label hosts without CIPSO headers, but only from processes | ||
187 | that have Smack write access to the host label. All packets | ||
188 | received from single label hosts are given the specified | ||
189 | label. The format accepted on write is: | ||
190 | "%d.%d.%d.%d label" or "%d.%d.%d.%d/%d label". | ||
191 | onlycap | ||
192 | This contains the label processes must have for CAP_MAC_ADMIN | ||
193 | and CAP_MAC_OVERRIDE to be effective. If this file is empty | ||
194 | these capabilities are effective at for processes with any | ||
195 | label. The value is set by writing the desired label to the | ||
196 | file or cleared by writing "-" to the file. | ||
77 | 197 | ||
78 | You can add access rules in /etc/smack/accesses. They take the form: | 198 | You can add access rules in /etc/smack/accesses. They take the form: |
79 | 199 | ||
@@ -83,10 +203,6 @@ access is a combination of the letters rwxa which specify the | |||
83 | kind of access permitted a subject with subjectlabel on an | 203 | kind of access permitted a subject with subjectlabel on an |
84 | object with objectlabel. If there is no rule no access is allowed. | 204 | object with objectlabel. If there is no rule no access is allowed. |
85 | 205 | ||
86 | A process can see the smack label it is running with by | ||
87 | reading /proc/self/attr/current. A privileged process can | ||
88 | set the process smack by writing there. | ||
89 | |||
90 | Look for additional programs on http://schaufler-ca.com | 206 | Look for additional programs on http://schaufler-ca.com |
91 | 207 | ||
92 | From the Smack Whitepaper: | 208 | From the Smack Whitepaper: |
@@ -186,7 +302,7 @@ team. Smack labels are unstructured, case sensitive, and the only operation | |||
186 | ever performed on them is comparison for equality. Smack labels cannot | 302 | ever performed on them is comparison for equality. Smack labels cannot |
187 | contain unprintable characters, the "/" (slash), the "\" (backslash), the "'" | 303 | contain unprintable characters, the "/" (slash), the "\" (backslash), the "'" |
188 | (quote) and '"' (double-quote) characters. | 304 | (quote) and '"' (double-quote) characters. |
189 | Smack labels cannot begin with a '-', which is reserved for special options. | 305 | Smack labels cannot begin with a '-'. This is reserved for special options. |
190 | 306 | ||
191 | There are some predefined labels: | 307 | There are some predefined labels: |
192 | 308 | ||
@@ -194,7 +310,7 @@ There are some predefined labels: | |||
194 | ^ Pronounced "hat", a single circumflex character. | 310 | ^ Pronounced "hat", a single circumflex character. |
195 | * Pronounced "star", a single asterisk character. | 311 | * Pronounced "star", a single asterisk character. |
196 | ? Pronounced "huh", a single question mark character. | 312 | ? Pronounced "huh", a single question mark character. |
197 | @ Pronounced "Internet", a single at sign character. | 313 | @ Pronounced "web", a single at sign character. |
198 | 314 | ||
199 | Every task on a Smack system is assigned a label. System tasks, such as | 315 | Every task on a Smack system is assigned a label. System tasks, such as |
200 | init(8) and systems daemons, are run with the floor ("_") label. User tasks | 316 | init(8) and systems daemons, are run with the floor ("_") label. User tasks |
@@ -246,13 +362,14 @@ The format of an access rule is: | |||
246 | 362 | ||
247 | Where subject-label is the Smack label of the task, object-label is the Smack | 363 | Where subject-label is the Smack label of the task, object-label is the Smack |
248 | label of the thing being accessed, and access is a string specifying the sort | 364 | label of the thing being accessed, and access is a string specifying the sort |
249 | of access allowed. The Smack labels are limited to 23 characters. The access | 365 | of access allowed. The access specification is searched for letters that |
250 | specification is searched for letters that describe access modes: | 366 | describe access modes: |
251 | 367 | ||
252 | a: indicates that append access should be granted. | 368 | a: indicates that append access should be granted. |
253 | r: indicates that read access should be granted. | 369 | r: indicates that read access should be granted. |
254 | w: indicates that write access should be granted. | 370 | w: indicates that write access should be granted. |
255 | x: indicates that execute access should be granted. | 371 | x: indicates that execute access should be granted. |
372 | t: indicates that the rule requests transmutation. | ||
256 | 373 | ||
257 | Uppercase values for the specification letters are allowed as well. | 374 | Uppercase values for the specification letters are allowed as well. |
258 | Access mode specifications can be in any order. Examples of acceptable rules | 375 | Access mode specifications can be in any order. Examples of acceptable rules |
@@ -273,7 +390,7 @@ Examples of unacceptable rules are: | |||
273 | 390 | ||
274 | Spaces are not allowed in labels. Since a subject always has access to files | 391 | Spaces are not allowed in labels. Since a subject always has access to files |
275 | with the same label specifying a rule for that case is pointless. Only | 392 | with the same label specifying a rule for that case is pointless. Only |
276 | valid letters (rwxaRWXA) and the dash ('-') character are allowed in | 393 | valid letters (rwxatRWXAT) and the dash ('-') character are allowed in |
277 | access specifications. The dash is a placeholder, so "a-r" is the same | 394 | access specifications. The dash is a placeholder, so "a-r" is the same |
278 | as "ar". A lone dash is used to specify that no access should be allowed. | 395 | as "ar". A lone dash is used to specify that no access should be allowed. |
279 | 396 | ||
@@ -297,6 +414,13 @@ but not any of its attributes by the circumstance of having read access to the | |||
297 | containing directory but not to the differently labeled file. This is an | 414 | containing directory but not to the differently labeled file. This is an |
298 | artifact of the file name being data in the directory, not a part of the file. | 415 | artifact of the file name being data in the directory, not a part of the file. |
299 | 416 | ||
417 | If a directory is marked as transmuting (SMACK64TRANSMUTE=TRUE) and the | ||
418 | access rule that allows a process to create an object in that directory | ||
419 | includes 't' access the label assigned to the new object will be that | ||
420 | of the directory, not the creating process. This makes it much easier | ||
421 | for two processes with different labels to share data without granting | ||
422 | access to all of their files. | ||
423 | |||
300 | IPC objects, message queues, semaphore sets, and memory segments exist in flat | 424 | IPC objects, message queues, semaphore sets, and memory segments exist in flat |
301 | namespaces and access requests are only required to match the object in | 425 | namespaces and access requests are only required to match the object in |
302 | question. | 426 | question. |
diff --git a/security/smack/smack.h b/security/smack/smack.h index 4ede719922ed..5e031a2e4c36 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -23,13 +23,19 @@ | |||
23 | #include <linux/lsm_audit.h> | 23 | #include <linux/lsm_audit.h> |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * Smack labels were limited to 23 characters for a long time. | ||
27 | */ | ||
28 | #define SMK_LABELLEN 24 | ||
29 | #define SMK_LONGLABEL 256 | ||
30 | |||
31 | /* | ||
32 | * Maximum number of bytes for the levels in a CIPSO IP option. | ||
26 | * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is | 33 | * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is |
27 | * bigger than can be used, and 24 is the next lower multiple | 34 | * bigger than can be used, and 24 is the next lower multiple |
28 | * of 8, and there are too many issues if there isn't space set | 35 | * of 8, and there are too many issues if there isn't space set |
29 | * aside for the terminating null byte. | 36 | * aside for the terminating null byte. |
30 | */ | 37 | */ |
31 | #define SMK_MAXLEN 23 | 38 | #define SMK_CIPSOLEN 24 |
32 | #define SMK_LABELLEN (SMK_MAXLEN+1) | ||
33 | 39 | ||
34 | struct superblock_smack { | 40 | struct superblock_smack { |
35 | char *smk_root; | 41 | char *smk_root; |
@@ -66,6 +72,7 @@ struct task_smack { | |||
66 | 72 | ||
67 | #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ | 73 | #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ |
68 | #define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */ | 74 | #define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */ |
75 | #define SMK_INODE_CHANGED 0x04 /* smack was transmuted */ | ||
69 | 76 | ||
70 | /* | 77 | /* |
71 | * A label access rule. | 78 | * A label access rule. |
@@ -78,15 +85,6 @@ struct smack_rule { | |||
78 | }; | 85 | }; |
79 | 86 | ||
80 | /* | 87 | /* |
81 | * An entry in the table mapping smack values to | ||
82 | * CIPSO level/category-set values. | ||
83 | */ | ||
84 | struct smack_cipso { | ||
85 | int smk_level; | ||
86 | char smk_catset[SMK_LABELLEN]; | ||
87 | }; | ||
88 | |||
89 | /* | ||
90 | * An entry in the table identifying hosts. | 88 | * An entry in the table identifying hosts. |
91 | */ | 89 | */ |
92 | struct smk_netlbladdr { | 90 | struct smk_netlbladdr { |
@@ -113,22 +111,19 @@ struct smk_netlbladdr { | |||
113 | * interfaces don't. The secid should go away when all of | 111 | * interfaces don't. The secid should go away when all of |
114 | * these components have been repaired. | 112 | * these components have been repaired. |
115 | * | 113 | * |
116 | * If there is a cipso value associated with the label it | 114 | * The cipso value associated with the label gets stored here, too. |
117 | * gets stored here, too. This will most likely be rare as | ||
118 | * the cipso direct mapping in used internally. | ||
119 | * | 115 | * |
120 | * Keep the access rules for this subject label here so that | 116 | * Keep the access rules for this subject label here so that |
121 | * the entire set of rules does not need to be examined every | 117 | * the entire set of rules does not need to be examined every |
122 | * time. | 118 | * time. |
123 | */ | 119 | */ |
124 | struct smack_known { | 120 | struct smack_known { |
125 | struct list_head list; | 121 | struct list_head list; |
126 | char smk_known[SMK_LABELLEN]; | 122 | char *smk_known; |
127 | u32 smk_secid; | 123 | u32 smk_secid; |
128 | struct smack_cipso *smk_cipso; | 124 | struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */ |
129 | spinlock_t smk_cipsolock; /* for changing cipso map */ | 125 | struct list_head smk_rules; /* access rules */ |
130 | struct list_head smk_rules; /* access rules */ | 126 | struct mutex smk_rules_lock; /* lock for rules */ |
131 | struct mutex smk_rules_lock; /* lock for the rules */ | ||
132 | }; | 127 | }; |
133 | 128 | ||
134 | /* | 129 | /* |
@@ -165,6 +160,7 @@ struct smack_known { | |||
165 | #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ | 160 | #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ |
166 | #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ | 161 | #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ |
167 | #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ | 162 | #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ |
163 | #define SMACK_CIPSO_MAPPED_DEFAULT 251 /* Also arbitrary */ | ||
168 | #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ | 164 | #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ |
169 | #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ | 165 | #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ |
170 | #define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */ | 166 | #define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */ |
@@ -215,10 +211,9 @@ struct inode_smack *new_inode_smack(char *); | |||
215 | int smk_access_entry(char *, char *, struct list_head *); | 211 | int smk_access_entry(char *, char *, struct list_head *); |
216 | int smk_access(char *, char *, int, struct smk_audit_info *); | 212 | int smk_access(char *, char *, int, struct smk_audit_info *); |
217 | int smk_curacc(char *, u32, struct smk_audit_info *); | 213 | int smk_curacc(char *, u32, struct smk_audit_info *); |
218 | int smack_to_cipso(const char *, struct smack_cipso *); | ||
219 | char *smack_from_cipso(u32, char *); | ||
220 | char *smack_from_secid(const u32); | 214 | char *smack_from_secid(const u32); |
221 | void smk_parse_smack(const char *string, int len, char *smack); | 215 | char *smk_parse_smack(const char *string, int len); |
216 | int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); | ||
222 | char *smk_import(const char *, int); | 217 | char *smk_import(const char *, int); |
223 | struct smack_known *smk_import_entry(const char *, int); | 218 | struct smack_known *smk_import_entry(const char *, int); |
224 | struct smack_known *smk_find_entry(const char *); | 219 | struct smack_known *smk_find_entry(const char *); |
@@ -228,6 +223,7 @@ u32 smack_to_secid(const char *); | |||
228 | * Shared data. | 223 | * Shared data. |
229 | */ | 224 | */ |
230 | extern int smack_cipso_direct; | 225 | extern int smack_cipso_direct; |
226 | extern int smack_cipso_mapped; | ||
231 | extern char *smack_net_ambient; | 227 | extern char *smack_net_ambient; |
232 | extern char *smack_onlycap; | 228 | extern char *smack_onlycap; |
233 | extern const char *smack_cipso_option; | 229 | extern const char *smack_cipso_option; |
@@ -239,24 +235,13 @@ extern struct smack_known smack_known_invalid; | |||
239 | extern struct smack_known smack_known_star; | 235 | extern struct smack_known smack_known_star; |
240 | extern struct smack_known smack_known_web; | 236 | extern struct smack_known smack_known_web; |
241 | 237 | ||
238 | extern struct mutex smack_known_lock; | ||
242 | extern struct list_head smack_known_list; | 239 | extern struct list_head smack_known_list; |
243 | extern struct list_head smk_netlbladdr_list; | 240 | extern struct list_head smk_netlbladdr_list; |
244 | 241 | ||
245 | extern struct security_operations smack_ops; | 242 | extern struct security_operations smack_ops; |
246 | 243 | ||
247 | /* | 244 | /* |
248 | * Stricly for CIPSO level manipulation. | ||
249 | * Set the category bit number in a smack label sized buffer. | ||
250 | */ | ||
251 | static inline void smack_catset_bit(int cat, char *catsetp) | ||
252 | { | ||
253 | if (cat > SMK_LABELLEN * 8) | ||
254 | return; | ||
255 | |||
256 | catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8); | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * Is the directory transmuting? | 245 | * Is the directory transmuting? |
261 | */ | 246 | */ |
262 | static inline int smk_inode_transmutable(const struct inode *isp) | 247 | static inline int smk_inode_transmutable(const struct inode *isp) |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index c8115f7308f8..9f3705e92712 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -19,37 +19,31 @@ | |||
19 | struct smack_known smack_known_huh = { | 19 | struct smack_known smack_known_huh = { |
20 | .smk_known = "?", | 20 | .smk_known = "?", |
21 | .smk_secid = 2, | 21 | .smk_secid = 2, |
22 | .smk_cipso = NULL, | ||
23 | }; | 22 | }; |
24 | 23 | ||
25 | struct smack_known smack_known_hat = { | 24 | struct smack_known smack_known_hat = { |
26 | .smk_known = "^", | 25 | .smk_known = "^", |
27 | .smk_secid = 3, | 26 | .smk_secid = 3, |
28 | .smk_cipso = NULL, | ||
29 | }; | 27 | }; |
30 | 28 | ||
31 | struct smack_known smack_known_star = { | 29 | struct smack_known smack_known_star = { |
32 | .smk_known = "*", | 30 | .smk_known = "*", |
33 | .smk_secid = 4, | 31 | .smk_secid = 4, |
34 | .smk_cipso = NULL, | ||
35 | }; | 32 | }; |
36 | 33 | ||
37 | struct smack_known smack_known_floor = { | 34 | struct smack_known smack_known_floor = { |
38 | .smk_known = "_", | 35 | .smk_known = "_", |
39 | .smk_secid = 5, | 36 | .smk_secid = 5, |
40 | .smk_cipso = NULL, | ||
41 | }; | 37 | }; |
42 | 38 | ||
43 | struct smack_known smack_known_invalid = { | 39 | struct smack_known smack_known_invalid = { |
44 | .smk_known = "", | 40 | .smk_known = "", |
45 | .smk_secid = 6, | 41 | .smk_secid = 6, |
46 | .smk_cipso = NULL, | ||
47 | }; | 42 | }; |
48 | 43 | ||
49 | struct smack_known smack_known_web = { | 44 | struct smack_known smack_known_web = { |
50 | .smk_known = "@", | 45 | .smk_known = "@", |
51 | .smk_secid = 7, | 46 | .smk_secid = 7, |
52 | .smk_cipso = NULL, | ||
53 | }; | 47 | }; |
54 | 48 | ||
55 | LIST_HEAD(smack_known_list); | 49 | LIST_HEAD(smack_known_list); |
@@ -331,7 +325,7 @@ void smack_log(char *subject_label, char *object_label, int request, | |||
331 | } | 325 | } |
332 | #endif | 326 | #endif |
333 | 327 | ||
334 | static DEFINE_MUTEX(smack_known_lock); | 328 | DEFINE_MUTEX(smack_known_lock); |
335 | 329 | ||
336 | /** | 330 | /** |
337 | * smk_find_entry - find a label on the list, return the list entry | 331 | * smk_find_entry - find a label on the list, return the list entry |
@@ -345,7 +339,7 @@ struct smack_known *smk_find_entry(const char *string) | |||
345 | struct smack_known *skp; | 339 | struct smack_known *skp; |
346 | 340 | ||
347 | list_for_each_entry_rcu(skp, &smack_known_list, list) { | 341 | list_for_each_entry_rcu(skp, &smack_known_list, list) { |
348 | if (strncmp(skp->smk_known, string, SMK_MAXLEN) == 0) | 342 | if (strcmp(skp->smk_known, string) == 0) |
349 | return skp; | 343 | return skp; |
350 | } | 344 | } |
351 | 345 | ||
@@ -356,27 +350,76 @@ struct smack_known *smk_find_entry(const char *string) | |||
356 | * smk_parse_smack - parse smack label from a text string | 350 | * smk_parse_smack - parse smack label from a text string |
357 | * @string: a text string that might contain a Smack label | 351 | * @string: a text string that might contain a Smack label |
358 | * @len: the maximum size, or zero if it is NULL terminated. | 352 | * @len: the maximum size, or zero if it is NULL terminated. |
359 | * @smack: parsed smack label, or NULL if parse error | 353 | * |
354 | * Returns a pointer to the clean label, or NULL | ||
360 | */ | 355 | */ |
361 | void smk_parse_smack(const char *string, int len, char *smack) | 356 | char *smk_parse_smack(const char *string, int len) |
362 | { | 357 | { |
363 | int found; | 358 | char *smack; |
364 | int i; | 359 | int i; |
365 | 360 | ||
366 | if (len <= 0 || len > SMK_MAXLEN) | 361 | if (len <= 0) |
367 | len = SMK_MAXLEN; | 362 | len = strlen(string) + 1; |
368 | 363 | ||
369 | for (i = 0, found = 0; i < SMK_LABELLEN; i++) { | 364 | /* |
370 | if (found) | 365 | * Reserve a leading '-' as an indicator that |
371 | smack[i] = '\0'; | 366 | * this isn't a label, but an option to interfaces |
372 | else if (i >= len || string[i] > '~' || string[i] <= ' ' || | 367 | * including /smack/cipso and /smack/cipso2 |
373 | string[i] == '/' || string[i] == '"' || | 368 | */ |
374 | string[i] == '\\' || string[i] == '\'') { | 369 | if (string[0] == '-') |
375 | smack[i] = '\0'; | 370 | return NULL; |
376 | found = 1; | 371 | |
377 | } else | 372 | for (i = 0; i < len; i++) |
378 | smack[i] = string[i]; | 373 | if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' || |
374 | string[i] == '"' || string[i] == '\\' || string[i] == '\'') | ||
375 | break; | ||
376 | |||
377 | if (i == 0 || i >= SMK_LONGLABEL) | ||
378 | return NULL; | ||
379 | |||
380 | smack = kzalloc(i + 1, GFP_KERNEL); | ||
381 | if (smack != NULL) { | ||
382 | strncpy(smack, string, i + 1); | ||
383 | smack[i] = '\0'; | ||
379 | } | 384 | } |
385 | return smack; | ||
386 | } | ||
387 | |||
388 | /** | ||
389 | * smk_netlbl_mls - convert a catset to netlabel mls categories | ||
390 | * @catset: the Smack categories | ||
391 | * @sap: where to put the netlabel categories | ||
392 | * | ||
393 | * Allocates and fills attr.mls | ||
394 | * Returns 0 on success, error code on failure. | ||
395 | */ | ||
396 | int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, | ||
397 | int len) | ||
398 | { | ||
399 | unsigned char *cp; | ||
400 | unsigned char m; | ||
401 | int cat; | ||
402 | int rc; | ||
403 | int byte; | ||
404 | |||
405 | sap->flags |= NETLBL_SECATTR_MLS_CAT; | ||
406 | sap->attr.mls.lvl = level; | ||
407 | sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
408 | sap->attr.mls.cat->startbit = 0; | ||
409 | |||
410 | for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++) | ||
411 | for (m = 0x80; m != 0; m >>= 1, cat++) { | ||
412 | if ((m & *cp) == 0) | ||
413 | continue; | ||
414 | rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat, | ||
415 | cat, GFP_ATOMIC); | ||
416 | if (rc < 0) { | ||
417 | netlbl_secattr_catmap_free(sap->attr.mls.cat); | ||
418 | return rc; | ||
419 | } | ||
420 | } | ||
421 | |||
422 | return 0; | ||
380 | } | 423 | } |
381 | 424 | ||
382 | /** | 425 | /** |
@@ -390,33 +433,59 @@ void smk_parse_smack(const char *string, int len, char *smack) | |||
390 | struct smack_known *smk_import_entry(const char *string, int len) | 433 | struct smack_known *smk_import_entry(const char *string, int len) |
391 | { | 434 | { |
392 | struct smack_known *skp; | 435 | struct smack_known *skp; |
393 | char smack[SMK_LABELLEN]; | 436 | char *smack; |
437 | int slen; | ||
438 | int rc; | ||
394 | 439 | ||
395 | smk_parse_smack(string, len, smack); | 440 | smack = smk_parse_smack(string, len); |
396 | if (smack[0] == '\0') | 441 | if (smack == NULL) |
397 | return NULL; | 442 | return NULL; |
398 | 443 | ||
399 | mutex_lock(&smack_known_lock); | 444 | mutex_lock(&smack_known_lock); |
400 | 445 | ||
401 | skp = smk_find_entry(smack); | 446 | skp = smk_find_entry(smack); |
447 | if (skp != NULL) | ||
448 | goto freeout; | ||
402 | 449 | ||
403 | if (skp == NULL) { | 450 | skp = kzalloc(sizeof(*skp), GFP_KERNEL); |
404 | skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); | 451 | if (skp == NULL) |
405 | if (skp != NULL) { | 452 | goto freeout; |
406 | strncpy(skp->smk_known, smack, SMK_MAXLEN); | ||
407 | skp->smk_secid = smack_next_secid++; | ||
408 | skp->smk_cipso = NULL; | ||
409 | INIT_LIST_HEAD(&skp->smk_rules); | ||
410 | spin_lock_init(&skp->smk_cipsolock); | ||
411 | mutex_init(&skp->smk_rules_lock); | ||
412 | /* | ||
413 | * Make sure that the entry is actually | ||
414 | * filled before putting it on the list. | ||
415 | */ | ||
416 | list_add_rcu(&skp->list, &smack_known_list); | ||
417 | } | ||
418 | } | ||
419 | 453 | ||
454 | skp->smk_known = smack; | ||
455 | skp->smk_secid = smack_next_secid++; | ||
456 | skp->smk_netlabel.domain = skp->smk_known; | ||
457 | skp->smk_netlabel.flags = | ||
458 | NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; | ||
459 | /* | ||
460 | * If direct labeling works use it. | ||
461 | * Otherwise use mapped labeling. | ||
462 | */ | ||
463 | slen = strlen(smack); | ||
464 | if (slen < SMK_CIPSOLEN) | ||
465 | rc = smk_netlbl_mls(smack_cipso_direct, skp->smk_known, | ||
466 | &skp->smk_netlabel, slen); | ||
467 | else | ||
468 | rc = smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid, | ||
469 | &skp->smk_netlabel, sizeof(skp->smk_secid)); | ||
470 | |||
471 | if (rc >= 0) { | ||
472 | INIT_LIST_HEAD(&skp->smk_rules); | ||
473 | mutex_init(&skp->smk_rules_lock); | ||
474 | /* | ||
475 | * Make sure that the entry is actually | ||
476 | * filled before putting it on the list. | ||
477 | */ | ||
478 | list_add_rcu(&skp->list, &smack_known_list); | ||
479 | goto unlockout; | ||
480 | } | ||
481 | /* | ||
482 | * smk_netlbl_mls failed. | ||
483 | */ | ||
484 | kfree(skp); | ||
485 | skp = NULL; | ||
486 | freeout: | ||
487 | kfree(smack); | ||
488 | unlockout: | ||
420 | mutex_unlock(&smack_known_lock); | 489 | mutex_unlock(&smack_known_lock); |
421 | 490 | ||
422 | return skp; | 491 | return skp; |
@@ -479,79 +548,9 @@ char *smack_from_secid(const u32 secid) | |||
479 | */ | 548 | */ |
480 | u32 smack_to_secid(const char *smack) | 549 | u32 smack_to_secid(const char *smack) |
481 | { | 550 | { |
482 | struct smack_known *skp; | 551 | struct smack_known *skp = smk_find_entry(smack); |
483 | 552 | ||
484 | rcu_read_lock(); | 553 | if (skp == NULL) |
485 | list_for_each_entry_rcu(skp, &smack_known_list, list) { | 554 | return 0; |
486 | if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { | 555 | return skp->smk_secid; |
487 | rcu_read_unlock(); | ||
488 | return skp->smk_secid; | ||
489 | } | ||
490 | } | ||
491 | rcu_read_unlock(); | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * smack_from_cipso - find the Smack label associated with a CIPSO option | ||
497 | * @level: Bell & LaPadula level from the network | ||
498 | * @cp: Bell & LaPadula categories from the network | ||
499 | * | ||
500 | * This is a simple lookup in the label table. | ||
501 | * | ||
502 | * Return the matching label from the label list or NULL. | ||
503 | */ | ||
504 | char *smack_from_cipso(u32 level, char *cp) | ||
505 | { | ||
506 | struct smack_known *kp; | ||
507 | char *final = NULL; | ||
508 | |||
509 | rcu_read_lock(); | ||
510 | list_for_each_entry(kp, &smack_known_list, list) { | ||
511 | if (kp->smk_cipso == NULL) | ||
512 | continue; | ||
513 | |||
514 | spin_lock_bh(&kp->smk_cipsolock); | ||
515 | |||
516 | if (kp->smk_cipso->smk_level == level && | ||
517 | memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0) | ||
518 | final = kp->smk_known; | ||
519 | |||
520 | spin_unlock_bh(&kp->smk_cipsolock); | ||
521 | |||
522 | if (final != NULL) | ||
523 | break; | ||
524 | } | ||
525 | rcu_read_unlock(); | ||
526 | |||
527 | return final; | ||
528 | } | ||
529 | |||
530 | /** | ||
531 | * smack_to_cipso - find the CIPSO option to go with a Smack label | ||
532 | * @smack: a pointer to the smack label in question | ||
533 | * @cp: where to put the result | ||
534 | * | ||
535 | * Returns zero if a value is available, non-zero otherwise. | ||
536 | */ | ||
537 | int smack_to_cipso(const char *smack, struct smack_cipso *cp) | ||
538 | { | ||
539 | struct smack_known *kp; | ||
540 | int found = 0; | ||
541 | |||
542 | rcu_read_lock(); | ||
543 | list_for_each_entry_rcu(kp, &smack_known_list, list) { | ||
544 | if (kp->smk_known == smack || | ||
545 | strcmp(kp->smk_known, smack) == 0) { | ||
546 | found = 1; | ||
547 | break; | ||
548 | } | ||
549 | } | ||
550 | rcu_read_unlock(); | ||
551 | |||
552 | if (found == 0 || kp->smk_cipso == NULL) | ||
553 | return -ENOENT; | ||
554 | |||
555 | memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso)); | ||
556 | return 0; | ||
557 | } | 556 | } |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 45c32f074166..952b1f41fc78 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
32 | #include <linux/pipe_fs_i.h> | 32 | #include <linux/pipe_fs_i.h> |
33 | #include <net/netlabel.h> | ||
34 | #include <net/cipso_ipv4.h> | 33 | #include <net/cipso_ipv4.h> |
35 | #include <linux/audit.h> | 34 | #include <linux/audit.h> |
36 | #include <linux/magic.h> | 35 | #include <linux/magic.h> |
@@ -57,16 +56,23 @@ | |||
57 | static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) | 56 | static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) |
58 | { | 57 | { |
59 | int rc; | 58 | int rc; |
60 | char in[SMK_LABELLEN]; | 59 | char *buffer; |
60 | char *result = NULL; | ||
61 | 61 | ||
62 | if (ip->i_op->getxattr == NULL) | 62 | if (ip->i_op->getxattr == NULL) |
63 | return NULL; | 63 | return NULL; |
64 | 64 | ||
65 | rc = ip->i_op->getxattr(dp, name, in, SMK_LABELLEN); | 65 | buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL); |
66 | if (rc < 0) | 66 | if (buffer == NULL) |
67 | return NULL; | 67 | return NULL; |
68 | 68 | ||
69 | return smk_import(in, rc); | 69 | rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL); |
70 | if (rc > 0) | ||
71 | result = smk_import(buffer, rc); | ||
72 | |||
73 | kfree(buffer); | ||
74 | |||
75 | return result; | ||
70 | } | 76 | } |
71 | 77 | ||
72 | /** | 78 | /** |
@@ -79,7 +85,7 @@ struct inode_smack *new_inode_smack(char *smack) | |||
79 | { | 85 | { |
80 | struct inode_smack *isp; | 86 | struct inode_smack *isp; |
81 | 87 | ||
82 | isp = kzalloc(sizeof(struct inode_smack), GFP_KERNEL); | 88 | isp = kzalloc(sizeof(struct inode_smack), GFP_NOFS); |
83 | if (isp == NULL) | 89 | if (isp == NULL) |
84 | return NULL; | 90 | return NULL; |
85 | 91 | ||
@@ -556,13 +562,14 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, | |||
556 | void **value, size_t *len) | 562 | void **value, size_t *len) |
557 | { | 563 | { |
558 | struct smack_known *skp; | 564 | struct smack_known *skp; |
565 | struct inode_smack *issp = inode->i_security; | ||
559 | char *csp = smk_of_current(); | 566 | char *csp = smk_of_current(); |
560 | char *isp = smk_of_inode(inode); | 567 | char *isp = smk_of_inode(inode); |
561 | char *dsp = smk_of_inode(dir); | 568 | char *dsp = smk_of_inode(dir); |
562 | int may; | 569 | int may; |
563 | 570 | ||
564 | if (name) { | 571 | if (name) { |
565 | *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL); | 572 | *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_NOFS); |
566 | if (*name == NULL) | 573 | if (*name == NULL) |
567 | return -ENOMEM; | 574 | return -ENOMEM; |
568 | } | 575 | } |
@@ -577,12 +584,15 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, | |||
577 | * If the access rule allows transmutation and | 584 | * If the access rule allows transmutation and |
578 | * the directory requests transmutation then | 585 | * the directory requests transmutation then |
579 | * by all means transmute. | 586 | * by all means transmute. |
587 | * Mark the inode as changed. | ||
580 | */ | 588 | */ |
581 | if (may > 0 && ((may & MAY_TRANSMUTE) != 0) && | 589 | if (may > 0 && ((may & MAY_TRANSMUTE) != 0) && |
582 | smk_inode_transmutable(dir)) | 590 | smk_inode_transmutable(dir)) { |
583 | isp = dsp; | 591 | isp = dsp; |
592 | issp->smk_flags |= SMK_INODE_CHANGED; | ||
593 | } | ||
584 | 594 | ||
585 | *value = kstrdup(isp, GFP_KERNEL); | 595 | *value = kstrdup(isp, GFP_NOFS); |
586 | if (*value == NULL) | 596 | if (*value == NULL) |
587 | return -ENOMEM; | 597 | return -ENOMEM; |
588 | } | 598 | } |
@@ -821,7 +831,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, | |||
821 | * check label validity here so import wont fail on | 831 | * check label validity here so import wont fail on |
822 | * post_setxattr | 832 | * post_setxattr |
823 | */ | 833 | */ |
824 | if (size == 0 || size >= SMK_LABELLEN || | 834 | if (size == 0 || size >= SMK_LONGLABEL || |
825 | smk_import(value, size) == NULL) | 835 | smk_import(value, size) == NULL) |
826 | rc = -EINVAL; | 836 | rc = -EINVAL; |
827 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { | 837 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { |
@@ -1820,65 +1830,6 @@ static char *smack_host_label(struct sockaddr_in *sip) | |||
1820 | } | 1830 | } |
1821 | 1831 | ||
1822 | /** | 1832 | /** |
1823 | * smack_set_catset - convert a capset to netlabel mls categories | ||
1824 | * @catset: the Smack categories | ||
1825 | * @sap: where to put the netlabel categories | ||
1826 | * | ||
1827 | * Allocates and fills attr.mls.cat | ||
1828 | */ | ||
1829 | static void smack_set_catset(char *catset, struct netlbl_lsm_secattr *sap) | ||
1830 | { | ||
1831 | unsigned char *cp; | ||
1832 | unsigned char m; | ||
1833 | int cat; | ||
1834 | int rc; | ||
1835 | int byte; | ||
1836 | |||
1837 | if (!catset) | ||
1838 | return; | ||
1839 | |||
1840 | sap->flags |= NETLBL_SECATTR_MLS_CAT; | ||
1841 | sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
1842 | sap->attr.mls.cat->startbit = 0; | ||
1843 | |||
1844 | for (cat = 1, cp = catset, byte = 0; byte < SMK_LABELLEN; cp++, byte++) | ||
1845 | for (m = 0x80; m != 0; m >>= 1, cat++) { | ||
1846 | if ((m & *cp) == 0) | ||
1847 | continue; | ||
1848 | rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat, | ||
1849 | cat, GFP_ATOMIC); | ||
1850 | } | ||
1851 | } | ||
1852 | |||
1853 | /** | ||
1854 | * smack_to_secattr - fill a secattr from a smack value | ||
1855 | * @smack: the smack value | ||
1856 | * @nlsp: where the result goes | ||
1857 | * | ||
1858 | * Casey says that CIPSO is good enough for now. | ||
1859 | * It can be used to effect. | ||
1860 | * It can also be abused to effect when necessary. | ||
1861 | * Apologies to the TSIG group in general and GW in particular. | ||
1862 | */ | ||
1863 | static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) | ||
1864 | { | ||
1865 | struct smack_cipso cipso; | ||
1866 | int rc; | ||
1867 | |||
1868 | nlsp->domain = smack; | ||
1869 | nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; | ||
1870 | |||
1871 | rc = smack_to_cipso(smack, &cipso); | ||
1872 | if (rc == 0) { | ||
1873 | nlsp->attr.mls.lvl = cipso.smk_level; | ||
1874 | smack_set_catset(cipso.smk_catset, nlsp); | ||
1875 | } else { | ||
1876 | nlsp->attr.mls.lvl = smack_cipso_direct; | ||
1877 | smack_set_catset(smack, nlsp); | ||
1878 | } | ||
1879 | } | ||
1880 | |||
1881 | /** | ||
1882 | * smack_netlabel - Set the secattr on a socket | 1833 | * smack_netlabel - Set the secattr on a socket |
1883 | * @sk: the socket | 1834 | * @sk: the socket |
1884 | * @labeled: socket label scheme | 1835 | * @labeled: socket label scheme |
@@ -1890,8 +1841,8 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) | |||
1890 | */ | 1841 | */ |
1891 | static int smack_netlabel(struct sock *sk, int labeled) | 1842 | static int smack_netlabel(struct sock *sk, int labeled) |
1892 | { | 1843 | { |
1844 | struct smack_known *skp; | ||
1893 | struct socket_smack *ssp = sk->sk_security; | 1845 | struct socket_smack *ssp = sk->sk_security; |
1894 | struct netlbl_lsm_secattr secattr; | ||
1895 | int rc = 0; | 1846 | int rc = 0; |
1896 | 1847 | ||
1897 | /* | 1848 | /* |
@@ -1909,10 +1860,8 @@ static int smack_netlabel(struct sock *sk, int labeled) | |||
1909 | labeled == SMACK_UNLABELED_SOCKET) | 1860 | labeled == SMACK_UNLABELED_SOCKET) |
1910 | netlbl_sock_delattr(sk); | 1861 | netlbl_sock_delattr(sk); |
1911 | else { | 1862 | else { |
1912 | netlbl_secattr_init(&secattr); | 1863 | skp = smk_find_entry(ssp->smk_out); |
1913 | smack_to_secattr(ssp->smk_out, &secattr); | 1864 | rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel); |
1914 | rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr); | ||
1915 | netlbl_secattr_destroy(&secattr); | ||
1916 | } | 1865 | } |
1917 | 1866 | ||
1918 | bh_unlock_sock(sk); | 1867 | bh_unlock_sock(sk); |
@@ -1985,7 +1934,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
1985 | struct socket *sock; | 1934 | struct socket *sock; |
1986 | int rc = 0; | 1935 | int rc = 0; |
1987 | 1936 | ||
1988 | if (value == NULL || size > SMK_LABELLEN || size == 0) | 1937 | if (value == NULL || size > SMK_LONGLABEL || size == 0) |
1989 | return -EACCES; | 1938 | return -EACCES; |
1990 | 1939 | ||
1991 | sp = smk_import(value, size); | 1940 | sp = smk_import(value, size); |
@@ -2552,6 +2501,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
2552 | char *final; | 2501 | char *final; |
2553 | char trattr[TRANS_TRUE_SIZE]; | 2502 | char trattr[TRANS_TRUE_SIZE]; |
2554 | int transflag = 0; | 2503 | int transflag = 0; |
2504 | int rc; | ||
2555 | struct dentry *dp; | 2505 | struct dentry *dp; |
2556 | 2506 | ||
2557 | if (inode == NULL) | 2507 | if (inode == NULL) |
@@ -2670,17 +2620,38 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
2670 | */ | 2620 | */ |
2671 | dp = dget(opt_dentry); | 2621 | dp = dget(opt_dentry); |
2672 | fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); | 2622 | fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); |
2673 | if (fetched != NULL) { | 2623 | if (fetched != NULL) |
2674 | final = fetched; | 2624 | final = fetched; |
2675 | if (S_ISDIR(inode->i_mode)) { | 2625 | |
2676 | trattr[0] = '\0'; | 2626 | /* |
2677 | inode->i_op->getxattr(dp, | 2627 | * Transmuting directory |
2628 | */ | ||
2629 | if (S_ISDIR(inode->i_mode)) { | ||
2630 | /* | ||
2631 | * If this is a new directory and the label was | ||
2632 | * transmuted when the inode was initialized | ||
2633 | * set the transmute attribute on the directory | ||
2634 | * and mark the inode. | ||
2635 | * | ||
2636 | * If there is a transmute attribute on the | ||
2637 | * directory mark the inode. | ||
2638 | */ | ||
2639 | if (isp->smk_flags & SMK_INODE_CHANGED) { | ||
2640 | isp->smk_flags &= ~SMK_INODE_CHANGED; | ||
2641 | rc = inode->i_op->setxattr(dp, | ||
2678 | XATTR_NAME_SMACKTRANSMUTE, | 2642 | XATTR_NAME_SMACKTRANSMUTE, |
2679 | trattr, TRANS_TRUE_SIZE); | 2643 | TRANS_TRUE, TRANS_TRUE_SIZE, |
2680 | if (strncmp(trattr, TRANS_TRUE, | 2644 | 0); |
2681 | TRANS_TRUE_SIZE) == 0) | 2645 | } else { |
2682 | transflag = SMK_INODE_TRANSMUTE; | 2646 | rc = inode->i_op->getxattr(dp, |
2647 | XATTR_NAME_SMACKTRANSMUTE, trattr, | ||
2648 | TRANS_TRUE_SIZE); | ||
2649 | if (rc >= 0 && strncmp(trattr, TRANS_TRUE, | ||
2650 | TRANS_TRUE_SIZE) != 0) | ||
2651 | rc = -EINVAL; | ||
2683 | } | 2652 | } |
2653 | if (rc >= 0) | ||
2654 | transflag = SMK_INODE_TRANSMUTE; | ||
2684 | } | 2655 | } |
2685 | isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); | 2656 | isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); |
2686 | isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); | 2657 | isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); |
@@ -2759,7 +2730,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
2759 | if (!capable(CAP_MAC_ADMIN)) | 2730 | if (!capable(CAP_MAC_ADMIN)) |
2760 | return -EPERM; | 2731 | return -EPERM; |
2761 | 2732 | ||
2762 | if (value == NULL || size == 0 || size >= SMK_LABELLEN) | 2733 | if (value == NULL || size == 0 || size >= SMK_LONGLABEL) |
2763 | return -EINVAL; | 2734 | return -EINVAL; |
2764 | 2735 | ||
2765 | if (strcmp(name, "current") != 0) | 2736 | if (strcmp(name, "current") != 0) |
@@ -2895,10 +2866,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, | |||
2895 | static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, | 2866 | static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, |
2896 | struct socket_smack *ssp) | 2867 | struct socket_smack *ssp) |
2897 | { | 2868 | { |
2898 | struct smack_known *skp; | 2869 | struct smack_known *kp; |
2899 | char smack[SMK_LABELLEN]; | ||
2900 | char *sp; | 2870 | char *sp; |
2901 | int pcat; | 2871 | int found = 0; |
2902 | 2872 | ||
2903 | if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { | 2873 | if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { |
2904 | /* | 2874 | /* |
@@ -2906,59 +2876,27 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, | |||
2906 | * If there are flags but no level netlabel isn't | 2876 | * If there are flags but no level netlabel isn't |
2907 | * behaving the way we expect it to. | 2877 | * behaving the way we expect it to. |
2908 | * | 2878 | * |
2909 | * Get the categories, if any | 2879 | * Look it up in the label table |
2910 | * Without guidance regarding the smack value | 2880 | * Without guidance regarding the smack value |
2911 | * for the packet fall back on the network | 2881 | * for the packet fall back on the network |
2912 | * ambient value. | 2882 | * ambient value. |
2913 | */ | 2883 | */ |
2914 | memset(smack, '\0', SMK_LABELLEN); | 2884 | rcu_read_lock(); |
2915 | if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0) | 2885 | list_for_each_entry(kp, &smack_known_list, list) { |
2916 | for (pcat = -1;;) { | 2886 | if (sap->attr.mls.lvl != kp->smk_netlabel.attr.mls.lvl) |
2917 | pcat = netlbl_secattr_catmap_walk( | 2887 | continue; |
2918 | sap->attr.mls.cat, pcat + 1); | 2888 | if (memcmp(sap->attr.mls.cat, |
2919 | if (pcat < 0) | 2889 | kp->smk_netlabel.attr.mls.cat, |
2920 | break; | 2890 | SMK_CIPSOLEN) != 0) |
2921 | smack_catset_bit(pcat, smack); | 2891 | continue; |
2922 | } | 2892 | found = 1; |
2923 | /* | 2893 | break; |
2924 | * If it is CIPSO using smack direct mapping | ||
2925 | * we are already done. WeeHee. | ||
2926 | */ | ||
2927 | if (sap->attr.mls.lvl == smack_cipso_direct) { | ||
2928 | /* | ||
2929 | * The label sent is usually on the label list. | ||
2930 | * | ||
2931 | * If it is not we may still want to allow the | ||
2932 | * delivery. | ||
2933 | * | ||
2934 | * If the recipient is accepting all packets | ||
2935 | * because it is using the star ("*") label | ||
2936 | * for SMACK64IPIN provide the web ("@") label | ||
2937 | * so that a directed response will succeed. | ||
2938 | * This is not very correct from a MAC point | ||
2939 | * of view, but gets around the problem that | ||
2940 | * locking prevents adding the newly discovered | ||
2941 | * label to the list. | ||
2942 | * The case where the recipient is not using | ||
2943 | * the star label should obviously fail. | ||
2944 | * The easy way to do this is to provide the | ||
2945 | * star label as the subject label. | ||
2946 | */ | ||
2947 | skp = smk_find_entry(smack); | ||
2948 | if (skp != NULL) | ||
2949 | return skp->smk_known; | ||
2950 | if (ssp != NULL && | ||
2951 | ssp->smk_in == smack_known_star.smk_known) | ||
2952 | return smack_known_web.smk_known; | ||
2953 | return smack_known_star.smk_known; | ||
2954 | } | 2894 | } |
2955 | /* | 2895 | rcu_read_unlock(); |
2956 | * Look it up in the supplied table if it is not | 2896 | |
2957 | * a direct mapping. | 2897 | if (found) |
2958 | */ | 2898 | return kp->smk_known; |
2959 | sp = smack_from_cipso(sap->attr.mls.lvl, smack); | 2899 | |
2960 | if (sp != NULL) | ||
2961 | return sp; | ||
2962 | if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known) | 2900 | if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known) |
2963 | return smack_known_web.smk_known; | 2901 | return smack_known_web.smk_known; |
2964 | return smack_known_star.smk_known; | 2902 | return smack_known_star.smk_known; |
@@ -3158,11 +3096,13 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
3158 | struct request_sock *req) | 3096 | struct request_sock *req) |
3159 | { | 3097 | { |
3160 | u16 family = sk->sk_family; | 3098 | u16 family = sk->sk_family; |
3099 | struct smack_known *skp; | ||
3161 | struct socket_smack *ssp = sk->sk_security; | 3100 | struct socket_smack *ssp = sk->sk_security; |
3162 | struct netlbl_lsm_secattr secattr; | 3101 | struct netlbl_lsm_secattr secattr; |
3163 | struct sockaddr_in addr; | 3102 | struct sockaddr_in addr; |
3164 | struct iphdr *hdr; | 3103 | struct iphdr *hdr; |
3165 | char *sp; | 3104 | char *sp; |
3105 | char *hsp; | ||
3166 | int rc; | 3106 | int rc; |
3167 | struct smk_audit_info ad; | 3107 | struct smk_audit_info ad; |
3168 | #ifdef CONFIG_AUDIT | 3108 | #ifdef CONFIG_AUDIT |
@@ -3209,16 +3149,14 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
3209 | hdr = ip_hdr(skb); | 3149 | hdr = ip_hdr(skb); |
3210 | addr.sin_addr.s_addr = hdr->saddr; | 3150 | addr.sin_addr.s_addr = hdr->saddr; |
3211 | rcu_read_lock(); | 3151 | rcu_read_lock(); |
3212 | if (smack_host_label(&addr) == NULL) { | 3152 | hsp = smack_host_label(&addr); |
3213 | rcu_read_unlock(); | 3153 | rcu_read_unlock(); |
3214 | netlbl_secattr_init(&secattr); | 3154 | |
3215 | smack_to_secattr(sp, &secattr); | 3155 | if (hsp == NULL) { |
3216 | rc = netlbl_req_setattr(req, &secattr); | 3156 | skp = smk_find_entry(sp); |
3217 | netlbl_secattr_destroy(&secattr); | 3157 | rc = netlbl_req_setattr(req, &skp->smk_netlabel); |
3218 | } else { | 3158 | } else |
3219 | rcu_read_unlock(); | ||
3220 | netlbl_req_delattr(req); | 3159 | netlbl_req_delattr(req); |
3221 | } | ||
3222 | 3160 | ||
3223 | return rc; | 3161 | return rc; |
3224 | } | 3162 | } |
@@ -3400,7 +3338,7 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, | |||
3400 | char *rule = vrule; | 3338 | char *rule = vrule; |
3401 | 3339 | ||
3402 | if (!rule) { | 3340 | if (!rule) { |
3403 | audit_log(actx, GFP_KERNEL, AUDIT_SELINUX_ERR, | 3341 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, |
3404 | "Smack: missing rule\n"); | 3342 | "Smack: missing rule\n"); |
3405 | return -ENOENT; | 3343 | return -ENOENT; |
3406 | } | 3344 | } |
@@ -3643,15 +3581,6 @@ struct security_operations smack_ops = { | |||
3643 | static __init void init_smack_known_list(void) | 3581 | static __init void init_smack_known_list(void) |
3644 | { | 3582 | { |
3645 | /* | 3583 | /* |
3646 | * Initialize CIPSO locks | ||
3647 | */ | ||
3648 | spin_lock_init(&smack_known_huh.smk_cipsolock); | ||
3649 | spin_lock_init(&smack_known_hat.smk_cipsolock); | ||
3650 | spin_lock_init(&smack_known_star.smk_cipsolock); | ||
3651 | spin_lock_init(&smack_known_floor.smk_cipsolock); | ||
3652 | spin_lock_init(&smack_known_invalid.smk_cipsolock); | ||
3653 | spin_lock_init(&smack_known_web.smk_cipsolock); | ||
3654 | /* | ||
3655 | * Initialize rule list locks | 3584 | * Initialize rule list locks |
3656 | */ | 3585 | */ |
3657 | mutex_init(&smack_known_huh.smk_rules_lock); | 3586 | mutex_init(&smack_known_huh.smk_rules_lock); |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 038811cb7e62..1810c9a4ed48 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
25 | #include <net/netlabel.h> | ||
26 | #include <net/cipso_ipv4.h> | 25 | #include <net/cipso_ipv4.h> |
27 | #include <linux/seq_file.h> | 26 | #include <linux/seq_file.h> |
28 | #include <linux/ctype.h> | 27 | #include <linux/ctype.h> |
@@ -45,6 +44,11 @@ enum smk_inos { | |||
45 | SMK_LOGGING = 10, /* logging */ | 44 | SMK_LOGGING = 10, /* logging */ |
46 | SMK_LOAD_SELF = 11, /* task specific rules */ | 45 | SMK_LOAD_SELF = 11, /* task specific rules */ |
47 | SMK_ACCESSES = 12, /* access policy */ | 46 | SMK_ACCESSES = 12, /* access policy */ |
47 | SMK_MAPPED = 13, /* CIPSO level indicating mapped label */ | ||
48 | SMK_LOAD2 = 14, /* load policy with long labels */ | ||
49 | SMK_LOAD_SELF2 = 15, /* load task specific rules with long labels */ | ||
50 | SMK_ACCESS2 = 16, /* make an access check with long labels */ | ||
51 | SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ | ||
48 | }; | 52 | }; |
49 | 53 | ||
50 | /* | 54 | /* |
@@ -60,7 +64,7 @@ static DEFINE_MUTEX(smk_netlbladdr_lock); | |||
60 | * If it isn't somehow marked, use this. | 64 | * If it isn't somehow marked, use this. |
61 | * It can be reset via smackfs/ambient | 65 | * It can be reset via smackfs/ambient |
62 | */ | 66 | */ |
63 | char *smack_net_ambient = smack_known_floor.smk_known; | 67 | char *smack_net_ambient; |
64 | 68 | ||
65 | /* | 69 | /* |
66 | * This is the level in a CIPSO header that indicates a | 70 | * This is the level in a CIPSO header that indicates a |
@@ -70,6 +74,13 @@ char *smack_net_ambient = smack_known_floor.smk_known; | |||
70 | int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; | 74 | int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; |
71 | 75 | ||
72 | /* | 76 | /* |
77 | * This is the level in a CIPSO header that indicates a | ||
78 | * secid is contained directly in the category set. | ||
79 | * It can be reset via smackfs/mapped | ||
80 | */ | ||
81 | int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT; | ||
82 | |||
83 | /* | ||
73 | * Unless a process is running with this label even | 84 | * Unless a process is running with this label even |
74 | * having CAP_MAC_OVERRIDE isn't enough to grant | 85 | * having CAP_MAC_OVERRIDE isn't enough to grant |
75 | * privilege to violate MAC policy. If no label is | 86 | * privilege to violate MAC policy. If no label is |
@@ -89,7 +100,7 @@ LIST_HEAD(smk_netlbladdr_list); | |||
89 | 100 | ||
90 | /* | 101 | /* |
91 | * Rule lists are maintained for each label. | 102 | * Rule lists are maintained for each label. |
92 | * This master list is just for reading /smack/load. | 103 | * This master list is just for reading /smack/load and /smack/load2. |
93 | */ | 104 | */ |
94 | struct smack_master_list { | 105 | struct smack_master_list { |
95 | struct list_head list; | 106 | struct list_head list; |
@@ -125,6 +136,18 @@ const char *smack_cipso_option = SMACK_CIPSO_OPTION; | |||
125 | #define SMK_OLOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_OACCESSLEN) | 136 | #define SMK_OLOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_OACCESSLEN) |
126 | #define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) | 137 | #define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) |
127 | 138 | ||
139 | /* | ||
140 | * Stricly for CIPSO level manipulation. | ||
141 | * Set the category bit number in a smack label sized buffer. | ||
142 | */ | ||
143 | static inline void smack_catset_bit(unsigned int cat, char *catsetp) | ||
144 | { | ||
145 | if (cat == 0 || cat > (SMK_CIPSOLEN * 8)) | ||
146 | return; | ||
147 | |||
148 | catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8); | ||
149 | } | ||
150 | |||
128 | /** | 151 | /** |
129 | * smk_netlabel_audit_set - fill a netlbl_audit struct | 152 | * smk_netlabel_audit_set - fill a netlbl_audit struct |
130 | * @nap: structure to fill | 153 | * @nap: structure to fill |
@@ -137,12 +160,10 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap) | |||
137 | } | 160 | } |
138 | 161 | ||
139 | /* | 162 | /* |
140 | * Values for parsing single label host rules | 163 | * Value for parsing single label host rules |
141 | * "1.2.3.4 X" | 164 | * "1.2.3.4 X" |
142 | * "192.168.138.129/32 abcdefghijklmnopqrstuvw" | ||
143 | */ | 165 | */ |
144 | #define SMK_NETLBLADDRMIN 9 | 166 | #define SMK_NETLBLADDRMIN 9 |
145 | #define SMK_NETLBLADDRMAX 42 | ||
146 | 167 | ||
147 | /** | 168 | /** |
148 | * smk_set_access - add a rule to the rule list | 169 | * smk_set_access - add a rule to the rule list |
@@ -188,33 +209,47 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list, | |||
188 | } | 209 | } |
189 | 210 | ||
190 | /** | 211 | /** |
191 | * smk_parse_rule - parse Smack rule from load string | 212 | * smk_fill_rule - Fill Smack rule from strings |
192 | * @data: string to be parsed whose size is SMK_LOADLEN | 213 | * @subject: subject label string |
214 | * @object: object label string | ||
215 | * @access: access string | ||
193 | * @rule: Smack rule | 216 | * @rule: Smack rule |
194 | * @import: if non-zero, import labels | 217 | * @import: if non-zero, import labels |
218 | * | ||
219 | * Returns 0 on success, -1 on failure | ||
195 | */ | 220 | */ |
196 | static int smk_parse_rule(const char *data, struct smack_rule *rule, int import) | 221 | static int smk_fill_rule(const char *subject, const char *object, |
222 | const char *access, struct smack_rule *rule, | ||
223 | int import) | ||
197 | { | 224 | { |
198 | char smack[SMK_LABELLEN]; | 225 | int rc = -1; |
226 | int done; | ||
227 | const char *cp; | ||
199 | struct smack_known *skp; | 228 | struct smack_known *skp; |
200 | 229 | ||
201 | if (import) { | 230 | if (import) { |
202 | rule->smk_subject = smk_import(data, 0); | 231 | rule->smk_subject = smk_import(subject, 0); |
203 | if (rule->smk_subject == NULL) | 232 | if (rule->smk_subject == NULL) |
204 | return -1; | 233 | return -1; |
205 | 234 | ||
206 | rule->smk_object = smk_import(data + SMK_LABELLEN, 0); | 235 | rule->smk_object = smk_import(object, 0); |
207 | if (rule->smk_object == NULL) | 236 | if (rule->smk_object == NULL) |
208 | return -1; | 237 | return -1; |
209 | } else { | 238 | } else { |
210 | smk_parse_smack(data, 0, smack); | 239 | cp = smk_parse_smack(subject, 0); |
211 | skp = smk_find_entry(smack); | 240 | if (cp == NULL) |
241 | return -1; | ||
242 | skp = smk_find_entry(cp); | ||
243 | kfree(cp); | ||
212 | if (skp == NULL) | 244 | if (skp == NULL) |
213 | return -1; | 245 | return -1; |
214 | rule->smk_subject = skp->smk_known; | 246 | rule->smk_subject = skp->smk_known; |
215 | 247 | ||
216 | smk_parse_smack(data + SMK_LABELLEN, 0, smack); | 248 | cp = smk_parse_smack(object, 0); |
217 | skp = smk_find_entry(smack); | 249 | if (cp == NULL) |
250 | return -1; | ||
251 | skp = smk_find_entry(cp); | ||
252 | kfree(cp); | ||
218 | if (skp == NULL) | 253 | if (skp == NULL) |
219 | return -1; | 254 | return -1; |
220 | rule->smk_object = skp->smk_known; | 255 | rule->smk_object = skp->smk_known; |
@@ -222,90 +257,127 @@ static int smk_parse_rule(const char *data, struct smack_rule *rule, int import) | |||
222 | 257 | ||
223 | rule->smk_access = 0; | 258 | rule->smk_access = 0; |
224 | 259 | ||
225 | switch (data[SMK_LABELLEN + SMK_LABELLEN]) { | 260 | for (cp = access, done = 0; *cp && !done; cp++) { |
226 | case '-': | 261 | switch (*cp) { |
227 | break; | 262 | case '-': |
228 | case 'r': | 263 | break; |
229 | case 'R': | 264 | case 'r': |
230 | rule->smk_access |= MAY_READ; | 265 | case 'R': |
231 | break; | 266 | rule->smk_access |= MAY_READ; |
232 | default: | 267 | break; |
233 | return -1; | 268 | case 'w': |
269 | case 'W': | ||
270 | rule->smk_access |= MAY_WRITE; | ||
271 | break; | ||
272 | case 'x': | ||
273 | case 'X': | ||
274 | rule->smk_access |= MAY_EXEC; | ||
275 | break; | ||
276 | case 'a': | ||
277 | case 'A': | ||
278 | rule->smk_access |= MAY_APPEND; | ||
279 | break; | ||
280 | case 't': | ||
281 | case 'T': | ||
282 | rule->smk_access |= MAY_TRANSMUTE; | ||
283 | break; | ||
284 | default: | ||
285 | done = 1; | ||
286 | break; | ||
287 | } | ||
234 | } | 288 | } |
289 | rc = 0; | ||
235 | 290 | ||
236 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { | 291 | return rc; |
237 | case '-': | 292 | } |
238 | break; | ||
239 | case 'w': | ||
240 | case 'W': | ||
241 | rule->smk_access |= MAY_WRITE; | ||
242 | break; | ||
243 | default: | ||
244 | return -1; | ||
245 | } | ||
246 | 293 | ||
247 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { | 294 | /** |
248 | case '-': | 295 | * smk_parse_rule - parse Smack rule from load string |
249 | break; | 296 | * @data: string to be parsed whose size is SMK_LOADLEN |
250 | case 'x': | 297 | * @rule: Smack rule |
251 | case 'X': | 298 | * @import: if non-zero, import labels |
252 | rule->smk_access |= MAY_EXEC; | 299 | * |
253 | break; | 300 | * Returns 0 on success, -1 on errors. |
254 | default: | 301 | */ |
255 | return -1; | 302 | static int smk_parse_rule(const char *data, struct smack_rule *rule, int import) |
256 | } | 303 | { |
304 | int rc; | ||
257 | 305 | ||
258 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { | 306 | rc = smk_fill_rule(data, data + SMK_LABELLEN, |
259 | case '-': | 307 | data + SMK_LABELLEN + SMK_LABELLEN, rule, import); |
260 | break; | 308 | return rc; |
261 | case 'a': | 309 | } |
262 | case 'A': | ||
263 | rule->smk_access |= MAY_APPEND; | ||
264 | break; | ||
265 | default: | ||
266 | return -1; | ||
267 | } | ||
268 | 310 | ||
269 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) { | 311 | /** |
270 | case '-': | 312 | * smk_parse_long_rule - parse Smack rule from rule string |
271 | break; | 313 | * @data: string to be parsed, null terminated |
272 | case 't': | 314 | * @rule: Smack rule |
273 | case 'T': | 315 | * @import: if non-zero, import labels |
274 | rule->smk_access |= MAY_TRANSMUTE; | 316 | * |
275 | break; | 317 | * Returns 0 on success, -1 on failure |
276 | default: | 318 | */ |
277 | return -1; | 319 | static int smk_parse_long_rule(const char *data, struct smack_rule *rule, |
278 | } | 320 | int import) |
321 | { | ||
322 | char *subject; | ||
323 | char *object; | ||
324 | char *access; | ||
325 | int datalen; | ||
326 | int rc = -1; | ||
279 | 327 | ||
280 | return 0; | 328 | /* |
329 | * This is probably inefficient, but safe. | ||
330 | */ | ||
331 | datalen = strlen(data); | ||
332 | subject = kzalloc(datalen, GFP_KERNEL); | ||
333 | if (subject == NULL) | ||
334 | return -1; | ||
335 | object = kzalloc(datalen, GFP_KERNEL); | ||
336 | if (object == NULL) | ||
337 | goto free_out_s; | ||
338 | access = kzalloc(datalen, GFP_KERNEL); | ||
339 | if (access == NULL) | ||
340 | goto free_out_o; | ||
341 | |||
342 | if (sscanf(data, "%s %s %s", subject, object, access) == 3) | ||
343 | rc = smk_fill_rule(subject, object, access, rule, import); | ||
344 | |||
345 | kfree(access); | ||
346 | free_out_o: | ||
347 | kfree(object); | ||
348 | free_out_s: | ||
349 | kfree(subject); | ||
350 | return rc; | ||
281 | } | 351 | } |
282 | 352 | ||
353 | #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ | ||
354 | #define SMK_LONG_FMT 1 /* Variable long label format */ | ||
283 | /** | 355 | /** |
284 | * smk_write_load_list - write() for any /smack/load | 356 | * smk_write_rules_list - write() for any /smack rule file |
285 | * @file: file pointer, not actually used | 357 | * @file: file pointer, not actually used |
286 | * @buf: where to get the data from | 358 | * @buf: where to get the data from |
287 | * @count: bytes sent | 359 | * @count: bytes sent |
288 | * @ppos: where to start - must be 0 | 360 | * @ppos: where to start - must be 0 |
289 | * @rule_list: the list of rules to write to | 361 | * @rule_list: the list of rules to write to |
290 | * @rule_lock: lock for the rule list | 362 | * @rule_lock: lock for the rule list |
363 | * @format: /smack/load or /smack/load2 format. | ||
291 | * | 364 | * |
292 | * Get one smack access rule from above. | 365 | * Get one smack access rule from above. |
293 | * The format is exactly: | 366 | * The format for SMK_LONG_FMT is: |
294 | * char subject[SMK_LABELLEN] | 367 | * "subject<whitespace>object<whitespace>access[<whitespace>...]" |
295 | * char object[SMK_LABELLEN] | 368 | * The format for SMK_FIXED24_FMT is exactly: |
296 | * char access[SMK_ACCESSLEN] | 369 | * "subject object rwxat" |
297 | * | ||
298 | * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes. | ||
299 | */ | 370 | */ |
300 | static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | 371 | static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, |
301 | size_t count, loff_t *ppos, | 372 | size_t count, loff_t *ppos, |
302 | struct list_head *rule_list, | 373 | struct list_head *rule_list, |
303 | struct mutex *rule_lock) | 374 | struct mutex *rule_lock, int format) |
304 | { | 375 | { |
305 | struct smack_master_list *smlp; | 376 | struct smack_master_list *smlp; |
306 | struct smack_known *skp; | 377 | struct smack_known *skp; |
307 | struct smack_rule *rule; | 378 | struct smack_rule *rule; |
308 | char *data; | 379 | char *data; |
380 | int datalen; | ||
309 | int rc = -EINVAL; | 381 | int rc = -EINVAL; |
310 | int load = 0; | 382 | int load = 0; |
311 | 383 | ||
@@ -315,13 +387,18 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
315 | */ | 387 | */ |
316 | if (*ppos != 0) | 388 | if (*ppos != 0) |
317 | return -EINVAL; | 389 | return -EINVAL; |
318 | /* | ||
319 | * Minor hack for backward compatibility | ||
320 | */ | ||
321 | if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN) | ||
322 | return -EINVAL; | ||
323 | 390 | ||
324 | data = kzalloc(SMK_LOADLEN, GFP_KERNEL); | 391 | if (format == SMK_FIXED24_FMT) { |
392 | /* | ||
393 | * Minor hack for backward compatibility | ||
394 | */ | ||
395 | if (count != SMK_OLOADLEN && count != SMK_LOADLEN) | ||
396 | return -EINVAL; | ||
397 | datalen = SMK_LOADLEN; | ||
398 | } else | ||
399 | datalen = count + 1; | ||
400 | |||
401 | data = kzalloc(datalen, GFP_KERNEL); | ||
325 | if (data == NULL) | 402 | if (data == NULL) |
326 | return -ENOMEM; | 403 | return -ENOMEM; |
327 | 404 | ||
@@ -330,20 +407,29 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
330 | goto out; | 407 | goto out; |
331 | } | 408 | } |
332 | 409 | ||
333 | /* | ||
334 | * More on the minor hack for backward compatibility | ||
335 | */ | ||
336 | if (count == (SMK_OLOADLEN)) | ||
337 | data[SMK_OLOADLEN] = '-'; | ||
338 | |||
339 | rule = kzalloc(sizeof(*rule), GFP_KERNEL); | 410 | rule = kzalloc(sizeof(*rule), GFP_KERNEL); |
340 | if (rule == NULL) { | 411 | if (rule == NULL) { |
341 | rc = -ENOMEM; | 412 | rc = -ENOMEM; |
342 | goto out; | 413 | goto out; |
343 | } | 414 | } |
344 | 415 | ||
345 | if (smk_parse_rule(data, rule, 1)) | 416 | if (format == SMK_LONG_FMT) { |
346 | goto out_free_rule; | 417 | /* |
418 | * Be sure the data string is terminated. | ||
419 | */ | ||
420 | data[count] = '\0'; | ||
421 | if (smk_parse_long_rule(data, rule, 1)) | ||
422 | goto out_free_rule; | ||
423 | } else { | ||
424 | /* | ||
425 | * More on the minor hack for backward compatibility | ||
426 | */ | ||
427 | if (count == (SMK_OLOADLEN)) | ||
428 | data[SMK_OLOADLEN] = '-'; | ||
429 | if (smk_parse_rule(data, rule, 1)) | ||
430 | goto out_free_rule; | ||
431 | } | ||
432 | |||
347 | 433 | ||
348 | if (rule_list == NULL) { | 434 | if (rule_list == NULL) { |
349 | load = 1; | 435 | load = 1; |
@@ -354,18 +440,20 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
354 | 440 | ||
355 | rc = count; | 441 | rc = count; |
356 | /* | 442 | /* |
357 | * If this is "load" as opposed to "load-self" and a new rule | 443 | * If this is a global as opposed to self and a new rule |
358 | * it needs to get added for reporting. | 444 | * it needs to get added for reporting. |
359 | * smk_set_access returns true if there was already a rule | 445 | * smk_set_access returns true if there was already a rule |
360 | * for the subject/object pair, and false if it was new. | 446 | * for the subject/object pair, and false if it was new. |
361 | */ | 447 | */ |
362 | if (load && !smk_set_access(rule, rule_list, rule_lock)) { | 448 | if (!smk_set_access(rule, rule_list, rule_lock)) { |
363 | smlp = kzalloc(sizeof(*smlp), GFP_KERNEL); | 449 | if (load) { |
364 | if (smlp != NULL) { | 450 | smlp = kzalloc(sizeof(*smlp), GFP_KERNEL); |
365 | smlp->smk_rule = rule; | 451 | if (smlp != NULL) { |
366 | list_add_rcu(&smlp->list, &smack_rule_list); | 452 | smlp->smk_rule = rule; |
367 | } else | 453 | list_add_rcu(&smlp->list, &smack_rule_list); |
368 | rc = -ENOMEM; | 454 | } else |
455 | rc = -ENOMEM; | ||
456 | } | ||
369 | goto out; | 457 | goto out; |
370 | } | 458 | } |
371 | 459 | ||
@@ -421,29 +509,18 @@ static void smk_seq_stop(struct seq_file *s, void *v) | |||
421 | /* No-op */ | 509 | /* No-op */ |
422 | } | 510 | } |
423 | 511 | ||
424 | /* | 512 | static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) |
425 | * Seq_file read operations for /smack/load | ||
426 | */ | ||
427 | |||
428 | static void *load_seq_start(struct seq_file *s, loff_t *pos) | ||
429 | { | ||
430 | return smk_seq_start(s, pos, &smack_rule_list); | ||
431 | } | ||
432 | |||
433 | static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
434 | { | 513 | { |
435 | return smk_seq_next(s, v, pos, &smack_rule_list); | 514 | /* |
436 | } | 515 | * Don't show any rules with label names too long for |
437 | 516 | * interface file (/smack/load or /smack/load2) | |
438 | static int load_seq_show(struct seq_file *s, void *v) | 517 | * because you should expect to be able to write |
439 | { | 518 | * anything you read back. |
440 | struct list_head *list = v; | 519 | */ |
441 | struct smack_master_list *smlp = | 520 | if (strlen(srp->smk_subject) >= max || strlen(srp->smk_object) >= max) |
442 | list_entry(list, struct smack_master_list, list); | 521 | return; |
443 | struct smack_rule *srp = smlp->smk_rule; | ||
444 | 522 | ||
445 | seq_printf(s, "%s %s", (char *)srp->smk_subject, | 523 | seq_printf(s, "%s %s", srp->smk_subject, srp->smk_object); |
446 | (char *)srp->smk_object); | ||
447 | 524 | ||
448 | seq_putc(s, ' '); | 525 | seq_putc(s, ' '); |
449 | 526 | ||
@@ -461,13 +538,36 @@ static int load_seq_show(struct seq_file *s, void *v) | |||
461 | seq_putc(s, '-'); | 538 | seq_putc(s, '-'); |
462 | 539 | ||
463 | seq_putc(s, '\n'); | 540 | seq_putc(s, '\n'); |
541 | } | ||
542 | |||
543 | /* | ||
544 | * Seq_file read operations for /smack/load | ||
545 | */ | ||
546 | |||
547 | static void *load2_seq_start(struct seq_file *s, loff_t *pos) | ||
548 | { | ||
549 | return smk_seq_start(s, pos, &smack_rule_list); | ||
550 | } | ||
551 | |||
552 | static void *load2_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
553 | { | ||
554 | return smk_seq_next(s, v, pos, &smack_rule_list); | ||
555 | } | ||
556 | |||
557 | static int load_seq_show(struct seq_file *s, void *v) | ||
558 | { | ||
559 | struct list_head *list = v; | ||
560 | struct smack_master_list *smlp = | ||
561 | list_entry(list, struct smack_master_list, list); | ||
562 | |||
563 | smk_rule_show(s, smlp->smk_rule, SMK_LABELLEN); | ||
464 | 564 | ||
465 | return 0; | 565 | return 0; |
466 | } | 566 | } |
467 | 567 | ||
468 | static const struct seq_operations load_seq_ops = { | 568 | static const struct seq_operations load_seq_ops = { |
469 | .start = load_seq_start, | 569 | .start = load2_seq_start, |
470 | .next = load_seq_next, | 570 | .next = load2_seq_next, |
471 | .show = load_seq_show, | 571 | .show = load_seq_show, |
472 | .stop = smk_seq_stop, | 572 | .stop = smk_seq_stop, |
473 | }; | 573 | }; |
@@ -504,7 +604,8 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
504 | if (!capable(CAP_MAC_ADMIN)) | 604 | if (!capable(CAP_MAC_ADMIN)) |
505 | return -EPERM; | 605 | return -EPERM; |
506 | 606 | ||
507 | return smk_write_load_list(file, buf, count, ppos, NULL, NULL); | 607 | return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, |
608 | SMK_FIXED24_FMT); | ||
508 | } | 609 | } |
509 | 610 | ||
510 | static const struct file_operations smk_load_ops = { | 611 | static const struct file_operations smk_load_ops = { |
@@ -574,6 +675,8 @@ static void smk_unlbl_ambient(char *oldambient) | |||
574 | printk(KERN_WARNING "%s:%d remove rc = %d\n", | 675 | printk(KERN_WARNING "%s:%d remove rc = %d\n", |
575 | __func__, __LINE__, rc); | 676 | __func__, __LINE__, rc); |
576 | } | 677 | } |
678 | if (smack_net_ambient == NULL) | ||
679 | smack_net_ambient = smack_known_floor.smk_known; | ||
577 | 680 | ||
578 | rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET, | 681 | rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET, |
579 | NULL, NULL, &nai); | 682 | NULL, NULL, &nai); |
@@ -605,27 +708,28 @@ static int cipso_seq_show(struct seq_file *s, void *v) | |||
605 | struct list_head *list = v; | 708 | struct list_head *list = v; |
606 | struct smack_known *skp = | 709 | struct smack_known *skp = |
607 | list_entry(list, struct smack_known, list); | 710 | list_entry(list, struct smack_known, list); |
608 | struct smack_cipso *scp = skp->smk_cipso; | 711 | struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; |
609 | char *cbp; | ||
610 | char sep = '/'; | 712 | char sep = '/'; |
611 | int cat = 1; | ||
612 | int i; | 713 | int i; |
613 | unsigned char m; | ||
614 | 714 | ||
615 | if (scp == NULL) | 715 | /* |
716 | * Don't show a label that could not have been set using | ||
717 | * /smack/cipso. This is in support of the notion that | ||
718 | * anything read from /smack/cipso ought to be writeable | ||
719 | * to /smack/cipso. | ||
720 | * | ||
721 | * /smack/cipso2 should be used instead. | ||
722 | */ | ||
723 | if (strlen(skp->smk_known) >= SMK_LABELLEN) | ||
616 | return 0; | 724 | return 0; |
617 | 725 | ||
618 | seq_printf(s, "%s %3d", (char *)&skp->smk_known, scp->smk_level); | 726 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); |
619 | 727 | ||
620 | cbp = scp->smk_catset; | 728 | for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; |
621 | for (i = 0; i < SMK_LABELLEN; i++) | 729 | i = netlbl_secattr_catmap_walk(cmp, i + 1)) { |
622 | for (m = 0x80; m != 0; m >>= 1) { | 730 | seq_printf(s, "%c%d", sep, i); |
623 | if (m & cbp[i]) { | 731 | sep = ','; |
624 | seq_printf(s, "%c%d", sep, cat); | 732 | } |
625 | sep = ','; | ||
626 | } | ||
627 | cat++; | ||
628 | } | ||
629 | 733 | ||
630 | seq_putc(s, '\n'); | 734 | seq_putc(s, '\n'); |
631 | 735 | ||
@@ -653,23 +757,24 @@ static int smk_open_cipso(struct inode *inode, struct file *file) | |||
653 | } | 757 | } |
654 | 758 | ||
655 | /** | 759 | /** |
656 | * smk_write_cipso - write() for /smack/cipso | 760 | * smk_set_cipso - do the work for write() for cipso and cipso2 |
657 | * @file: file pointer, not actually used | 761 | * @file: file pointer, not actually used |
658 | * @buf: where to get the data from | 762 | * @buf: where to get the data from |
659 | * @count: bytes sent | 763 | * @count: bytes sent |
660 | * @ppos: where to start | 764 | * @ppos: where to start |
765 | * @format: /smack/cipso or /smack/cipso2 | ||
661 | * | 766 | * |
662 | * Accepts only one cipso rule per write call. | 767 | * Accepts only one cipso rule per write call. |
663 | * Returns number of bytes written or error code, as appropriate | 768 | * Returns number of bytes written or error code, as appropriate |
664 | */ | 769 | */ |
665 | static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | 770 | static ssize_t smk_set_cipso(struct file *file, const char __user *buf, |
666 | size_t count, loff_t *ppos) | 771 | size_t count, loff_t *ppos, int format) |
667 | { | 772 | { |
668 | struct smack_known *skp; | 773 | struct smack_known *skp; |
669 | struct smack_cipso *scp = NULL; | 774 | struct netlbl_lsm_secattr ncats; |
670 | char mapcatset[SMK_LABELLEN]; | 775 | char mapcatset[SMK_CIPSOLEN]; |
671 | int maplevel; | 776 | int maplevel; |
672 | int cat; | 777 | unsigned int cat; |
673 | int catlen; | 778 | int catlen; |
674 | ssize_t rc = -EINVAL; | 779 | ssize_t rc = -EINVAL; |
675 | char *data = NULL; | 780 | char *data = NULL; |
@@ -686,7 +791,8 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | |||
686 | return -EPERM; | 791 | return -EPERM; |
687 | if (*ppos != 0) | 792 | if (*ppos != 0) |
688 | return -EINVAL; | 793 | return -EINVAL; |
689 | if (count < SMK_CIPSOMIN || count > SMK_CIPSOMAX) | 794 | if (format == SMK_FIXED24_FMT && |
795 | (count < SMK_CIPSOMIN || count > SMK_CIPSOMAX)) | ||
690 | return -EINVAL; | 796 | return -EINVAL; |
691 | 797 | ||
692 | data = kzalloc(count + 1, GFP_KERNEL); | 798 | data = kzalloc(count + 1, GFP_KERNEL); |
@@ -698,11 +804,6 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | |||
698 | goto unlockedout; | 804 | goto unlockedout; |
699 | } | 805 | } |
700 | 806 | ||
701 | /* labels cannot begin with a '-' */ | ||
702 | if (data[0] == '-') { | ||
703 | rc = -EINVAL; | ||
704 | goto unlockedout; | ||
705 | } | ||
706 | data[count] = '\0'; | 807 | data[count] = '\0'; |
707 | rule = data; | 808 | rule = data; |
708 | /* | 809 | /* |
@@ -715,7 +816,11 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | |||
715 | if (skp == NULL) | 816 | if (skp == NULL) |
716 | goto out; | 817 | goto out; |
717 | 818 | ||
718 | rule += SMK_LABELLEN; | 819 | if (format == SMK_FIXED24_FMT) |
820 | rule += SMK_LABELLEN; | ||
821 | else | ||
822 | rule += strlen(skp->smk_known); | ||
823 | |||
719 | ret = sscanf(rule, "%d", &maplevel); | 824 | ret = sscanf(rule, "%d", &maplevel); |
720 | if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL) | 825 | if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL) |
721 | goto out; | 826 | goto out; |
@@ -725,41 +830,29 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | |||
725 | if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM) | 830 | if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM) |
726 | goto out; | 831 | goto out; |
727 | 832 | ||
728 | if (count != (SMK_CIPSOMIN + catlen * SMK_DIGITLEN)) | 833 | if (format == SMK_FIXED24_FMT && |
834 | count != (SMK_CIPSOMIN + catlen * SMK_DIGITLEN)) | ||
729 | goto out; | 835 | goto out; |
730 | 836 | ||
731 | memset(mapcatset, 0, sizeof(mapcatset)); | 837 | memset(mapcatset, 0, sizeof(mapcatset)); |
732 | 838 | ||
733 | for (i = 0; i < catlen; i++) { | 839 | for (i = 0; i < catlen; i++) { |
734 | rule += SMK_DIGITLEN; | 840 | rule += SMK_DIGITLEN; |
735 | ret = sscanf(rule, "%d", &cat); | 841 | ret = sscanf(rule, "%u", &cat); |
736 | if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL) | 842 | if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL) |
737 | goto out; | 843 | goto out; |
738 | 844 | ||
739 | smack_catset_bit(cat, mapcatset); | 845 | smack_catset_bit(cat, mapcatset); |
740 | } | 846 | } |
741 | 847 | ||
742 | if (skp->smk_cipso == NULL) { | 848 | rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN); |
743 | scp = kzalloc(sizeof(struct smack_cipso), GFP_KERNEL); | 849 | if (rc >= 0) { |
744 | if (scp == NULL) { | 850 | netlbl_secattr_catmap_free(skp->smk_netlabel.attr.mls.cat); |
745 | rc = -ENOMEM; | 851 | skp->smk_netlabel.attr.mls.cat = ncats.attr.mls.cat; |
746 | goto out; | 852 | skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl; |
747 | } | 853 | rc = count; |
748 | } | 854 | } |
749 | 855 | ||
750 | spin_lock_bh(&skp->smk_cipsolock); | ||
751 | |||
752 | if (scp == NULL) | ||
753 | scp = skp->smk_cipso; | ||
754 | else | ||
755 | skp->smk_cipso = scp; | ||
756 | |||
757 | scp->smk_level = maplevel; | ||
758 | memcpy(scp->smk_catset, mapcatset, sizeof(mapcatset)); | ||
759 | |||
760 | spin_unlock_bh(&skp->smk_cipsolock); | ||
761 | |||
762 | rc = count; | ||
763 | out: | 856 | out: |
764 | mutex_unlock(&smack_cipso_lock); | 857 | mutex_unlock(&smack_cipso_lock); |
765 | unlockedout: | 858 | unlockedout: |
@@ -767,6 +860,22 @@ unlockedout: | |||
767 | return rc; | 860 | return rc; |
768 | } | 861 | } |
769 | 862 | ||
863 | /** | ||
864 | * smk_write_cipso - write() for /smack/cipso | ||
865 | * @file: file pointer, not actually used | ||
866 | * @buf: where to get the data from | ||
867 | * @count: bytes sent | ||
868 | * @ppos: where to start | ||
869 | * | ||
870 | * Accepts only one cipso rule per write call. | ||
871 | * Returns number of bytes written or error code, as appropriate | ||
872 | */ | ||
873 | static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | ||
874 | size_t count, loff_t *ppos) | ||
875 | { | ||
876 | return smk_set_cipso(file, buf, count, ppos, SMK_FIXED24_FMT); | ||
877 | } | ||
878 | |||
770 | static const struct file_operations smk_cipso_ops = { | 879 | static const struct file_operations smk_cipso_ops = { |
771 | .open = smk_open_cipso, | 880 | .open = smk_open_cipso, |
772 | .read = seq_read, | 881 | .read = seq_read, |
@@ -776,6 +885,80 @@ static const struct file_operations smk_cipso_ops = { | |||
776 | }; | 885 | }; |
777 | 886 | ||
778 | /* | 887 | /* |
888 | * Seq_file read operations for /smack/cipso2 | ||
889 | */ | ||
890 | |||
891 | /* | ||
892 | * Print cipso labels in format: | ||
893 | * label level[/cat[,cat]] | ||
894 | */ | ||
895 | static int cipso2_seq_show(struct seq_file *s, void *v) | ||
896 | { | ||
897 | struct list_head *list = v; | ||
898 | struct smack_known *skp = | ||
899 | list_entry(list, struct smack_known, list); | ||
900 | struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; | ||
901 | char sep = '/'; | ||
902 | int i; | ||
903 | |||
904 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); | ||
905 | |||
906 | for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; | ||
907 | i = netlbl_secattr_catmap_walk(cmp, i + 1)) { | ||
908 | seq_printf(s, "%c%d", sep, i); | ||
909 | sep = ','; | ||
910 | } | ||
911 | |||
912 | seq_putc(s, '\n'); | ||
913 | |||
914 | return 0; | ||
915 | } | ||
916 | |||
917 | static const struct seq_operations cipso2_seq_ops = { | ||
918 | .start = cipso_seq_start, | ||
919 | .next = cipso_seq_next, | ||
920 | .show = cipso2_seq_show, | ||
921 | .stop = smk_seq_stop, | ||
922 | }; | ||
923 | |||
924 | /** | ||
925 | * smk_open_cipso2 - open() for /smack/cipso2 | ||
926 | * @inode: inode structure representing file | ||
927 | * @file: "cipso2" file pointer | ||
928 | * | ||
929 | * Connect our cipso_seq_* operations with /smack/cipso2 | ||
930 | * file_operations | ||
931 | */ | ||
932 | static int smk_open_cipso2(struct inode *inode, struct file *file) | ||
933 | { | ||
934 | return seq_open(file, &cipso2_seq_ops); | ||
935 | } | ||
936 | |||
937 | /** | ||
938 | * smk_write_cipso2 - write() for /smack/cipso2 | ||
939 | * @file: file pointer, not actually used | ||
940 | * @buf: where to get the data from | ||
941 | * @count: bytes sent | ||
942 | * @ppos: where to start | ||
943 | * | ||
944 | * Accepts only one cipso rule per write call. | ||
945 | * Returns number of bytes written or error code, as appropriate | ||
946 | */ | ||
947 | static ssize_t smk_write_cipso2(struct file *file, const char __user *buf, | ||
948 | size_t count, loff_t *ppos) | ||
949 | { | ||
950 | return smk_set_cipso(file, buf, count, ppos, SMK_LONG_FMT); | ||
951 | } | ||
952 | |||
953 | static const struct file_operations smk_cipso2_ops = { | ||
954 | .open = smk_open_cipso2, | ||
955 | .read = seq_read, | ||
956 | .llseek = seq_lseek, | ||
957 | .write = smk_write_cipso2, | ||
958 | .release = seq_release, | ||
959 | }; | ||
960 | |||
961 | /* | ||
779 | * Seq_file read operations for /smack/netlabel | 962 | * Seq_file read operations for /smack/netlabel |
780 | */ | 963 | */ |
781 | 964 | ||
@@ -887,9 +1070,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
887 | { | 1070 | { |
888 | struct smk_netlbladdr *skp; | 1071 | struct smk_netlbladdr *skp; |
889 | struct sockaddr_in newname; | 1072 | struct sockaddr_in newname; |
890 | char smack[SMK_LABELLEN]; | 1073 | char *smack; |
891 | char *sp; | 1074 | char *sp; |
892 | char data[SMK_NETLBLADDRMAX + 1]; | 1075 | char *data; |
893 | char *host = (char *)&newname.sin_addr.s_addr; | 1076 | char *host = (char *)&newname.sin_addr.s_addr; |
894 | int rc; | 1077 | int rc; |
895 | struct netlbl_audit audit_info; | 1078 | struct netlbl_audit audit_info; |
@@ -911,10 +1094,23 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
911 | return -EPERM; | 1094 | return -EPERM; |
912 | if (*ppos != 0) | 1095 | if (*ppos != 0) |
913 | return -EINVAL; | 1096 | return -EINVAL; |
914 | if (count < SMK_NETLBLADDRMIN || count > SMK_NETLBLADDRMAX) | 1097 | if (count < SMK_NETLBLADDRMIN) |
915 | return -EINVAL; | 1098 | return -EINVAL; |
916 | if (copy_from_user(data, buf, count) != 0) | 1099 | |
917 | return -EFAULT; | 1100 | data = kzalloc(count + 1, GFP_KERNEL); |
1101 | if (data == NULL) | ||
1102 | return -ENOMEM; | ||
1103 | |||
1104 | if (copy_from_user(data, buf, count) != 0) { | ||
1105 | rc = -EFAULT; | ||
1106 | goto free_data_out; | ||
1107 | } | ||
1108 | |||
1109 | smack = kzalloc(count + 1, GFP_KERNEL); | ||
1110 | if (smack == NULL) { | ||
1111 | rc = -ENOMEM; | ||
1112 | goto free_data_out; | ||
1113 | } | ||
918 | 1114 | ||
919 | data[count] = '\0'; | 1115 | data[count] = '\0'; |
920 | 1116 | ||
@@ -923,24 +1119,34 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
923 | if (rc != 6) { | 1119 | if (rc != 6) { |
924 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", | 1120 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", |
925 | &host[0], &host[1], &host[2], &host[3], smack); | 1121 | &host[0], &host[1], &host[2], &host[3], smack); |
926 | if (rc != 5) | 1122 | if (rc != 5) { |
927 | return -EINVAL; | 1123 | rc = -EINVAL; |
1124 | goto free_out; | ||
1125 | } | ||
928 | m = BEBITS; | 1126 | m = BEBITS; |
929 | } | 1127 | } |
930 | if (m > BEBITS) | 1128 | if (m > BEBITS) { |
931 | return -EINVAL; | 1129 | rc = -EINVAL; |
1130 | goto free_out; | ||
1131 | } | ||
932 | 1132 | ||
933 | /* if smack begins with '-', its an option, don't import it */ | 1133 | /* |
1134 | * If smack begins with '-', it is an option, don't import it | ||
1135 | */ | ||
934 | if (smack[0] != '-') { | 1136 | if (smack[0] != '-') { |
935 | sp = smk_import(smack, 0); | 1137 | sp = smk_import(smack, 0); |
936 | if (sp == NULL) | 1138 | if (sp == NULL) { |
937 | return -EINVAL; | 1139 | rc = -EINVAL; |
1140 | goto free_out; | ||
1141 | } | ||
938 | } else { | 1142 | } else { |
939 | /* check known options */ | 1143 | /* check known options */ |
940 | if (strcmp(smack, smack_cipso_option) == 0) | 1144 | if (strcmp(smack, smack_cipso_option) == 0) |
941 | sp = (char *)smack_cipso_option; | 1145 | sp = (char *)smack_cipso_option; |
942 | else | 1146 | else { |
943 | return -EINVAL; | 1147 | rc = -EINVAL; |
1148 | goto free_out; | ||
1149 | } | ||
944 | } | 1150 | } |
945 | 1151 | ||
946 | for (temp_mask = 0; m > 0; m--) { | 1152 | for (temp_mask = 0; m > 0; m--) { |
@@ -1006,6 +1212,11 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1006 | 1212 | ||
1007 | mutex_unlock(&smk_netlbladdr_lock); | 1213 | mutex_unlock(&smk_netlbladdr_lock); |
1008 | 1214 | ||
1215 | free_out: | ||
1216 | kfree(smack); | ||
1217 | free_data_out: | ||
1218 | kfree(data); | ||
1219 | |||
1009 | return rc; | 1220 | return rc; |
1010 | } | 1221 | } |
1011 | 1222 | ||
@@ -1119,6 +1330,7 @@ static ssize_t smk_read_direct(struct file *filp, char __user *buf, | |||
1119 | static ssize_t smk_write_direct(struct file *file, const char __user *buf, | 1330 | static ssize_t smk_write_direct(struct file *file, const char __user *buf, |
1120 | size_t count, loff_t *ppos) | 1331 | size_t count, loff_t *ppos) |
1121 | { | 1332 | { |
1333 | struct smack_known *skp; | ||
1122 | char temp[80]; | 1334 | char temp[80]; |
1123 | int i; | 1335 | int i; |
1124 | 1336 | ||
@@ -1136,7 +1348,20 @@ static ssize_t smk_write_direct(struct file *file, const char __user *buf, | |||
1136 | if (sscanf(temp, "%d", &i) != 1) | 1348 | if (sscanf(temp, "%d", &i) != 1) |
1137 | return -EINVAL; | 1349 | return -EINVAL; |
1138 | 1350 | ||
1139 | smack_cipso_direct = i; | 1351 | /* |
1352 | * Don't do anything if the value hasn't actually changed. | ||
1353 | * If it is changing reset the level on entries that were | ||
1354 | * set up to be direct when they were created. | ||
1355 | */ | ||
1356 | if (smack_cipso_direct != i) { | ||
1357 | mutex_lock(&smack_known_lock); | ||
1358 | list_for_each_entry_rcu(skp, &smack_known_list, list) | ||
1359 | if (skp->smk_netlabel.attr.mls.lvl == | ||
1360 | smack_cipso_direct) | ||
1361 | skp->smk_netlabel.attr.mls.lvl = i; | ||
1362 | smack_cipso_direct = i; | ||
1363 | mutex_unlock(&smack_known_lock); | ||
1364 | } | ||
1140 | 1365 | ||
1141 | return count; | 1366 | return count; |
1142 | } | 1367 | } |
@@ -1148,6 +1373,84 @@ static const struct file_operations smk_direct_ops = { | |||
1148 | }; | 1373 | }; |
1149 | 1374 | ||
1150 | /** | 1375 | /** |
1376 | * smk_read_mapped - read() for /smack/mapped | ||
1377 | * @filp: file pointer, not actually used | ||
1378 | * @buf: where to put the result | ||
1379 | * @count: maximum to send along | ||
1380 | * @ppos: where to start | ||
1381 | * | ||
1382 | * Returns number of bytes read or error code, as appropriate | ||
1383 | */ | ||
1384 | static ssize_t smk_read_mapped(struct file *filp, char __user *buf, | ||
1385 | size_t count, loff_t *ppos) | ||
1386 | { | ||
1387 | char temp[80]; | ||
1388 | ssize_t rc; | ||
1389 | |||
1390 | if (*ppos != 0) | ||
1391 | return 0; | ||
1392 | |||
1393 | sprintf(temp, "%d", smack_cipso_mapped); | ||
1394 | rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); | ||
1395 | |||
1396 | return rc; | ||
1397 | } | ||
1398 | |||
1399 | /** | ||
1400 | * smk_write_mapped - write() for /smack/mapped | ||
1401 | * @file: file pointer, not actually used | ||
1402 | * @buf: where to get the data from | ||
1403 | * @count: bytes sent | ||
1404 | * @ppos: where to start | ||
1405 | * | ||
1406 | * Returns number of bytes written or error code, as appropriate | ||
1407 | */ | ||
1408 | static ssize_t smk_write_mapped(struct file *file, const char __user *buf, | ||
1409 | size_t count, loff_t *ppos) | ||
1410 | { | ||
1411 | struct smack_known *skp; | ||
1412 | char temp[80]; | ||
1413 | int i; | ||
1414 | |||
1415 | if (!capable(CAP_MAC_ADMIN)) | ||
1416 | return -EPERM; | ||
1417 | |||
1418 | if (count >= sizeof(temp) || count == 0) | ||
1419 | return -EINVAL; | ||
1420 | |||
1421 | if (copy_from_user(temp, buf, count) != 0) | ||
1422 | return -EFAULT; | ||
1423 | |||
1424 | temp[count] = '\0'; | ||
1425 | |||
1426 | if (sscanf(temp, "%d", &i) != 1) | ||
1427 | return -EINVAL; | ||
1428 | |||
1429 | /* | ||
1430 | * Don't do anything if the value hasn't actually changed. | ||
1431 | * If it is changing reset the level on entries that were | ||
1432 | * set up to be mapped when they were created. | ||
1433 | */ | ||
1434 | if (smack_cipso_mapped != i) { | ||
1435 | mutex_lock(&smack_known_lock); | ||
1436 | list_for_each_entry_rcu(skp, &smack_known_list, list) | ||
1437 | if (skp->smk_netlabel.attr.mls.lvl == | ||
1438 | smack_cipso_mapped) | ||
1439 | skp->smk_netlabel.attr.mls.lvl = i; | ||
1440 | smack_cipso_mapped = i; | ||
1441 | mutex_unlock(&smack_known_lock); | ||
1442 | } | ||
1443 | |||
1444 | return count; | ||
1445 | } | ||
1446 | |||
1447 | static const struct file_operations smk_mapped_ops = { | ||
1448 | .read = smk_read_mapped, | ||
1449 | .write = smk_write_mapped, | ||
1450 | .llseek = default_llseek, | ||
1451 | }; | ||
1452 | |||
1453 | /** | ||
1151 | * smk_read_ambient - read() for /smack/ambient | 1454 | * smk_read_ambient - read() for /smack/ambient |
1152 | * @filp: file pointer, not actually used | 1455 | * @filp: file pointer, not actually used |
1153 | * @buf: where to put the result | 1456 | * @buf: where to put the result |
@@ -1195,22 +1498,28 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf, | |||
1195 | static ssize_t smk_write_ambient(struct file *file, const char __user *buf, | 1498 | static ssize_t smk_write_ambient(struct file *file, const char __user *buf, |
1196 | size_t count, loff_t *ppos) | 1499 | size_t count, loff_t *ppos) |
1197 | { | 1500 | { |
1198 | char in[SMK_LABELLEN]; | ||
1199 | char *oldambient; | 1501 | char *oldambient; |
1200 | char *smack; | 1502 | char *smack = NULL; |
1503 | char *data; | ||
1504 | int rc = count; | ||
1201 | 1505 | ||
1202 | if (!capable(CAP_MAC_ADMIN)) | 1506 | if (!capable(CAP_MAC_ADMIN)) |
1203 | return -EPERM; | 1507 | return -EPERM; |
1204 | 1508 | ||
1205 | if (count >= SMK_LABELLEN) | 1509 | data = kzalloc(count + 1, GFP_KERNEL); |
1206 | return -EINVAL; | 1510 | if (data == NULL) |
1511 | return -ENOMEM; | ||
1207 | 1512 | ||
1208 | if (copy_from_user(in, buf, count) != 0) | 1513 | if (copy_from_user(data, buf, count) != 0) { |
1209 | return -EFAULT; | 1514 | rc = -EFAULT; |
1515 | goto out; | ||
1516 | } | ||
1210 | 1517 | ||
1211 | smack = smk_import(in, count); | 1518 | smack = smk_import(data, count); |
1212 | if (smack == NULL) | 1519 | if (smack == NULL) { |
1213 | return -EINVAL; | 1520 | rc = -EINVAL; |
1521 | goto out; | ||
1522 | } | ||
1214 | 1523 | ||
1215 | mutex_lock(&smack_ambient_lock); | 1524 | mutex_lock(&smack_ambient_lock); |
1216 | 1525 | ||
@@ -1220,7 +1529,9 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, | |||
1220 | 1529 | ||
1221 | mutex_unlock(&smack_ambient_lock); | 1530 | mutex_unlock(&smack_ambient_lock); |
1222 | 1531 | ||
1223 | return count; | 1532 | out: |
1533 | kfree(data); | ||
1534 | return rc; | ||
1224 | } | 1535 | } |
1225 | 1536 | ||
1226 | static const struct file_operations smk_ambient_ops = { | 1537 | static const struct file_operations smk_ambient_ops = { |
@@ -1271,8 +1582,9 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, | |||
1271 | static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | 1582 | static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, |
1272 | size_t count, loff_t *ppos) | 1583 | size_t count, loff_t *ppos) |
1273 | { | 1584 | { |
1274 | char in[SMK_LABELLEN]; | 1585 | char *data; |
1275 | char *sp = smk_of_task(current->cred->security); | 1586 | char *sp = smk_of_task(current->cred->security); |
1587 | int rc = count; | ||
1276 | 1588 | ||
1277 | if (!capable(CAP_MAC_ADMIN)) | 1589 | if (!capable(CAP_MAC_ADMIN)) |
1278 | return -EPERM; | 1590 | return -EPERM; |
@@ -1285,11 +1597,9 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
1285 | if (smack_onlycap != NULL && smack_onlycap != sp) | 1597 | if (smack_onlycap != NULL && smack_onlycap != sp) |
1286 | return -EPERM; | 1598 | return -EPERM; |
1287 | 1599 | ||
1288 | if (count >= SMK_LABELLEN) | 1600 | data = kzalloc(count, GFP_KERNEL); |
1289 | return -EINVAL; | 1601 | if (data == NULL) |
1290 | 1602 | return -ENOMEM; | |
1291 | if (copy_from_user(in, buf, count) != 0) | ||
1292 | return -EFAULT; | ||
1293 | 1603 | ||
1294 | /* | 1604 | /* |
1295 | * Should the null string be passed in unset the onlycap value. | 1605 | * Should the null string be passed in unset the onlycap value. |
@@ -1297,10 +1607,17 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
1297 | * smk_import only expects to return NULL for errors. It | 1607 | * smk_import only expects to return NULL for errors. It |
1298 | * is usually the case that a nullstring or "\n" would be | 1608 | * is usually the case that a nullstring or "\n" would be |
1299 | * bad to pass to smk_import but in fact this is useful here. | 1609 | * bad to pass to smk_import but in fact this is useful here. |
1610 | * | ||
1611 | * smk_import will also reject a label beginning with '-', | ||
1612 | * so "-usecapabilities" will also work. | ||
1300 | */ | 1613 | */ |
1301 | smack_onlycap = smk_import(in, count); | 1614 | if (copy_from_user(data, buf, count) != 0) |
1615 | rc = -EFAULT; | ||
1616 | else | ||
1617 | smack_onlycap = smk_import(data, count); | ||
1302 | 1618 | ||
1303 | return count; | 1619 | kfree(data); |
1620 | return rc; | ||
1304 | } | 1621 | } |
1305 | 1622 | ||
1306 | static const struct file_operations smk_onlycap_ops = { | 1623 | static const struct file_operations smk_onlycap_ops = { |
@@ -1398,25 +1715,7 @@ static int load_self_seq_show(struct seq_file *s, void *v) | |||
1398 | struct smack_rule *srp = | 1715 | struct smack_rule *srp = |
1399 | list_entry(list, struct smack_rule, list); | 1716 | list_entry(list, struct smack_rule, list); |
1400 | 1717 | ||
1401 | seq_printf(s, "%s %s", (char *)srp->smk_subject, | 1718 | smk_rule_show(s, srp, SMK_LABELLEN); |
1402 | (char *)srp->smk_object); | ||
1403 | |||
1404 | seq_putc(s, ' '); | ||
1405 | |||
1406 | if (srp->smk_access & MAY_READ) | ||
1407 | seq_putc(s, 'r'); | ||
1408 | if (srp->smk_access & MAY_WRITE) | ||
1409 | seq_putc(s, 'w'); | ||
1410 | if (srp->smk_access & MAY_EXEC) | ||
1411 | seq_putc(s, 'x'); | ||
1412 | if (srp->smk_access & MAY_APPEND) | ||
1413 | seq_putc(s, 'a'); | ||
1414 | if (srp->smk_access & MAY_TRANSMUTE) | ||
1415 | seq_putc(s, 't'); | ||
1416 | if (srp->smk_access == 0) | ||
1417 | seq_putc(s, '-'); | ||
1418 | |||
1419 | seq_putc(s, '\n'); | ||
1420 | 1719 | ||
1421 | return 0; | 1720 | return 0; |
1422 | } | 1721 | } |
@@ -1430,7 +1729,7 @@ static const struct seq_operations load_self_seq_ops = { | |||
1430 | 1729 | ||
1431 | 1730 | ||
1432 | /** | 1731 | /** |
1433 | * smk_open_load_self - open() for /smack/load-self | 1732 | * smk_open_load_self - open() for /smack/load-self2 |
1434 | * @inode: inode structure representing file | 1733 | * @inode: inode structure representing file |
1435 | * @file: "load" file pointer | 1734 | * @file: "load" file pointer |
1436 | * | 1735 | * |
@@ -1454,8 +1753,8 @@ static ssize_t smk_write_load_self(struct file *file, const char __user *buf, | |||
1454 | { | 1753 | { |
1455 | struct task_smack *tsp = current_security(); | 1754 | struct task_smack *tsp = current_security(); |
1456 | 1755 | ||
1457 | return smk_write_load_list(file, buf, count, ppos, &tsp->smk_rules, | 1756 | return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, |
1458 | &tsp->smk_rules_lock); | 1757 | &tsp->smk_rules_lock, SMK_FIXED24_FMT); |
1459 | } | 1758 | } |
1460 | 1759 | ||
1461 | static const struct file_operations smk_load_self_ops = { | 1760 | static const struct file_operations smk_load_self_ops = { |
@@ -1467,24 +1766,42 @@ static const struct file_operations smk_load_self_ops = { | |||
1467 | }; | 1766 | }; |
1468 | 1767 | ||
1469 | /** | 1768 | /** |
1470 | * smk_write_access - handle access check transaction | 1769 | * smk_user_access - handle access check transaction |
1471 | * @file: file pointer | 1770 | * @file: file pointer |
1472 | * @buf: data from user space | 1771 | * @buf: data from user space |
1473 | * @count: bytes sent | 1772 | * @count: bytes sent |
1474 | * @ppos: where to start - must be 0 | 1773 | * @ppos: where to start - must be 0 |
1475 | */ | 1774 | */ |
1476 | static ssize_t smk_write_access(struct file *file, const char __user *buf, | 1775 | static ssize_t smk_user_access(struct file *file, const char __user *buf, |
1477 | size_t count, loff_t *ppos) | 1776 | size_t count, loff_t *ppos, int format) |
1478 | { | 1777 | { |
1479 | struct smack_rule rule; | 1778 | struct smack_rule rule; |
1480 | char *data; | 1779 | char *data; |
1780 | char *cod; | ||
1481 | int res; | 1781 | int res; |
1482 | 1782 | ||
1483 | data = simple_transaction_get(file, buf, count); | 1783 | data = simple_transaction_get(file, buf, count); |
1484 | if (IS_ERR(data)) | 1784 | if (IS_ERR(data)) |
1485 | return PTR_ERR(data); | 1785 | return PTR_ERR(data); |
1486 | 1786 | ||
1487 | if (count < SMK_LOADLEN || smk_parse_rule(data, &rule, 0)) | 1787 | if (format == SMK_FIXED24_FMT) { |
1788 | if (count < SMK_LOADLEN) | ||
1789 | return -EINVAL; | ||
1790 | res = smk_parse_rule(data, &rule, 0); | ||
1791 | } else { | ||
1792 | /* | ||
1793 | * Copy the data to make sure the string is terminated. | ||
1794 | */ | ||
1795 | cod = kzalloc(count + 1, GFP_KERNEL); | ||
1796 | if (cod == NULL) | ||
1797 | return -ENOMEM; | ||
1798 | memcpy(cod, data, count); | ||
1799 | cod[count] = '\0'; | ||
1800 | res = smk_parse_long_rule(cod, &rule, 0); | ||
1801 | kfree(cod); | ||
1802 | } | ||
1803 | |||
1804 | if (res) | ||
1488 | return -EINVAL; | 1805 | return -EINVAL; |
1489 | 1806 | ||
1490 | res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access, | 1807 | res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access, |
@@ -1493,7 +1810,23 @@ static ssize_t smk_write_access(struct file *file, const char __user *buf, | |||
1493 | data[1] = '\0'; | 1810 | data[1] = '\0'; |
1494 | 1811 | ||
1495 | simple_transaction_set(file, 2); | 1812 | simple_transaction_set(file, 2); |
1496 | return SMK_LOADLEN; | 1813 | |
1814 | if (format == SMK_FIXED24_FMT) | ||
1815 | return SMK_LOADLEN; | ||
1816 | return count; | ||
1817 | } | ||
1818 | |||
1819 | /** | ||
1820 | * smk_write_access - handle access check transaction | ||
1821 | * @file: file pointer | ||
1822 | * @buf: data from user space | ||
1823 | * @count: bytes sent | ||
1824 | * @ppos: where to start - must be 0 | ||
1825 | */ | ||
1826 | static ssize_t smk_write_access(struct file *file, const char __user *buf, | ||
1827 | size_t count, loff_t *ppos) | ||
1828 | { | ||
1829 | return smk_user_access(file, buf, count, ppos, SMK_FIXED24_FMT); | ||
1497 | } | 1830 | } |
1498 | 1831 | ||
1499 | static const struct file_operations smk_access_ops = { | 1832 | static const struct file_operations smk_access_ops = { |
@@ -1503,6 +1836,163 @@ static const struct file_operations smk_access_ops = { | |||
1503 | .llseek = generic_file_llseek, | 1836 | .llseek = generic_file_llseek, |
1504 | }; | 1837 | }; |
1505 | 1838 | ||
1839 | |||
1840 | /* | ||
1841 | * Seq_file read operations for /smack/load2 | ||
1842 | */ | ||
1843 | |||
1844 | static int load2_seq_show(struct seq_file *s, void *v) | ||
1845 | { | ||
1846 | struct list_head *list = v; | ||
1847 | struct smack_master_list *smlp = | ||
1848 | list_entry(list, struct smack_master_list, list); | ||
1849 | |||
1850 | smk_rule_show(s, smlp->smk_rule, SMK_LONGLABEL); | ||
1851 | |||
1852 | return 0; | ||
1853 | } | ||
1854 | |||
1855 | static const struct seq_operations load2_seq_ops = { | ||
1856 | .start = load2_seq_start, | ||
1857 | .next = load2_seq_next, | ||
1858 | .show = load2_seq_show, | ||
1859 | .stop = smk_seq_stop, | ||
1860 | }; | ||
1861 | |||
1862 | /** | ||
1863 | * smk_open_load2 - open() for /smack/load2 | ||
1864 | * @inode: inode structure representing file | ||
1865 | * @file: "load2" file pointer | ||
1866 | * | ||
1867 | * For reading, use load2_seq_* seq_file reading operations. | ||
1868 | */ | ||
1869 | static int smk_open_load2(struct inode *inode, struct file *file) | ||
1870 | { | ||
1871 | return seq_open(file, &load2_seq_ops); | ||
1872 | } | ||
1873 | |||
1874 | /** | ||
1875 | * smk_write_load2 - write() for /smack/load2 | ||
1876 | * @file: file pointer, not actually used | ||
1877 | * @buf: where to get the data from | ||
1878 | * @count: bytes sent | ||
1879 | * @ppos: where to start - must be 0 | ||
1880 | * | ||
1881 | */ | ||
1882 | static ssize_t smk_write_load2(struct file *file, const char __user *buf, | ||
1883 | size_t count, loff_t *ppos) | ||
1884 | { | ||
1885 | /* | ||
1886 | * Must have privilege. | ||
1887 | */ | ||
1888 | if (!capable(CAP_MAC_ADMIN)) | ||
1889 | return -EPERM; | ||
1890 | |||
1891 | return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, | ||
1892 | SMK_LONG_FMT); | ||
1893 | } | ||
1894 | |||
1895 | static const struct file_operations smk_load2_ops = { | ||
1896 | .open = smk_open_load2, | ||
1897 | .read = seq_read, | ||
1898 | .llseek = seq_lseek, | ||
1899 | .write = smk_write_load2, | ||
1900 | .release = seq_release, | ||
1901 | }; | ||
1902 | |||
1903 | /* | ||
1904 | * Seq_file read operations for /smack/load-self2 | ||
1905 | */ | ||
1906 | |||
1907 | static void *load_self2_seq_start(struct seq_file *s, loff_t *pos) | ||
1908 | { | ||
1909 | struct task_smack *tsp = current_security(); | ||
1910 | |||
1911 | return smk_seq_start(s, pos, &tsp->smk_rules); | ||
1912 | } | ||
1913 | |||
1914 | static void *load_self2_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
1915 | { | ||
1916 | struct task_smack *tsp = current_security(); | ||
1917 | |||
1918 | return smk_seq_next(s, v, pos, &tsp->smk_rules); | ||
1919 | } | ||
1920 | |||
1921 | static int load_self2_seq_show(struct seq_file *s, void *v) | ||
1922 | { | ||
1923 | struct list_head *list = v; | ||
1924 | struct smack_rule *srp = | ||
1925 | list_entry(list, struct smack_rule, list); | ||
1926 | |||
1927 | smk_rule_show(s, srp, SMK_LONGLABEL); | ||
1928 | |||
1929 | return 0; | ||
1930 | } | ||
1931 | |||
1932 | static const struct seq_operations load_self2_seq_ops = { | ||
1933 | .start = load_self2_seq_start, | ||
1934 | .next = load_self2_seq_next, | ||
1935 | .show = load_self2_seq_show, | ||
1936 | .stop = smk_seq_stop, | ||
1937 | }; | ||
1938 | |||
1939 | /** | ||
1940 | * smk_open_load_self2 - open() for /smack/load-self2 | ||
1941 | * @inode: inode structure representing file | ||
1942 | * @file: "load" file pointer | ||
1943 | * | ||
1944 | * For reading, use load_seq_* seq_file reading operations. | ||
1945 | */ | ||
1946 | static int smk_open_load_self2(struct inode *inode, struct file *file) | ||
1947 | { | ||
1948 | return seq_open(file, &load_self2_seq_ops); | ||
1949 | } | ||
1950 | |||
1951 | /** | ||
1952 | * smk_write_load_self2 - write() for /smack/load-self2 | ||
1953 | * @file: file pointer, not actually used | ||
1954 | * @buf: where to get the data from | ||
1955 | * @count: bytes sent | ||
1956 | * @ppos: where to start - must be 0 | ||
1957 | * | ||
1958 | */ | ||
1959 | static ssize_t smk_write_load_self2(struct file *file, const char __user *buf, | ||
1960 | size_t count, loff_t *ppos) | ||
1961 | { | ||
1962 | struct task_smack *tsp = current_security(); | ||
1963 | |||
1964 | return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, | ||
1965 | &tsp->smk_rules_lock, SMK_LONG_FMT); | ||
1966 | } | ||
1967 | |||
1968 | static const struct file_operations smk_load_self2_ops = { | ||
1969 | .open = smk_open_load_self2, | ||
1970 | .read = seq_read, | ||
1971 | .llseek = seq_lseek, | ||
1972 | .write = smk_write_load_self2, | ||
1973 | .release = seq_release, | ||
1974 | }; | ||
1975 | |||
1976 | /** | ||
1977 | * smk_write_access2 - handle access check transaction | ||
1978 | * @file: file pointer | ||
1979 | * @buf: data from user space | ||
1980 | * @count: bytes sent | ||
1981 | * @ppos: where to start - must be 0 | ||
1982 | */ | ||
1983 | static ssize_t smk_write_access2(struct file *file, const char __user *buf, | ||
1984 | size_t count, loff_t *ppos) | ||
1985 | { | ||
1986 | return smk_user_access(file, buf, count, ppos, SMK_LONG_FMT); | ||
1987 | } | ||
1988 | |||
1989 | static const struct file_operations smk_access2_ops = { | ||
1990 | .write = smk_write_access2, | ||
1991 | .read = simple_transaction_read, | ||
1992 | .release = simple_transaction_release, | ||
1993 | .llseek = generic_file_llseek, | ||
1994 | }; | ||
1995 | |||
1506 | /** | 1996 | /** |
1507 | * smk_fill_super - fill the /smackfs superblock | 1997 | * smk_fill_super - fill the /smackfs superblock |
1508 | * @sb: the empty superblock | 1998 | * @sb: the empty superblock |
@@ -1539,6 +2029,16 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
1539 | "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO}, | 2029 | "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO}, |
1540 | [SMK_ACCESSES] = { | 2030 | [SMK_ACCESSES] = { |
1541 | "access", &smk_access_ops, S_IRUGO|S_IWUGO}, | 2031 | "access", &smk_access_ops, S_IRUGO|S_IWUGO}, |
2032 | [SMK_MAPPED] = { | ||
2033 | "mapped", &smk_mapped_ops, S_IRUGO|S_IWUSR}, | ||
2034 | [SMK_LOAD2] = { | ||
2035 | "load2", &smk_load2_ops, S_IRUGO|S_IWUSR}, | ||
2036 | [SMK_LOAD_SELF2] = { | ||
2037 | "load-self2", &smk_load_self2_ops, S_IRUGO|S_IWUGO}, | ||
2038 | [SMK_ACCESS2] = { | ||
2039 | "access2", &smk_access2_ops, S_IRUGO|S_IWUGO}, | ||
2040 | [SMK_CIPSO2] = { | ||
2041 | "cipso2", &smk_cipso2_ops, S_IRUGO|S_IWUSR}, | ||
1542 | /* last one */ | 2042 | /* last one */ |
1543 | {""} | 2043 | {""} |
1544 | }; | 2044 | }; |
@@ -1581,6 +2081,15 @@ static struct file_system_type smk_fs_type = { | |||
1581 | 2081 | ||
1582 | static struct vfsmount *smackfs_mount; | 2082 | static struct vfsmount *smackfs_mount; |
1583 | 2083 | ||
2084 | static int __init smk_preset_netlabel(struct smack_known *skp) | ||
2085 | { | ||
2086 | skp->smk_netlabel.domain = skp->smk_known; | ||
2087 | skp->smk_netlabel.flags = | ||
2088 | NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; | ||
2089 | return smk_netlbl_mls(smack_cipso_direct, skp->smk_known, | ||
2090 | &skp->smk_netlabel, strlen(skp->smk_known)); | ||
2091 | } | ||
2092 | |||
1584 | /** | 2093 | /** |
1585 | * init_smk_fs - get the smackfs superblock | 2094 | * init_smk_fs - get the smackfs superblock |
1586 | * | 2095 | * |
@@ -1597,6 +2106,7 @@ static struct vfsmount *smackfs_mount; | |||
1597 | static int __init init_smk_fs(void) | 2106 | static int __init init_smk_fs(void) |
1598 | { | 2107 | { |
1599 | int err; | 2108 | int err; |
2109 | int rc; | ||
1600 | 2110 | ||
1601 | if (!security_module_enable(&smack_ops)) | 2111 | if (!security_module_enable(&smack_ops)) |
1602 | return 0; | 2112 | return 0; |
@@ -1614,6 +2124,25 @@ static int __init init_smk_fs(void) | |||
1614 | smk_cipso_doi(); | 2124 | smk_cipso_doi(); |
1615 | smk_unlbl_ambient(NULL); | 2125 | smk_unlbl_ambient(NULL); |
1616 | 2126 | ||
2127 | rc = smk_preset_netlabel(&smack_known_floor); | ||
2128 | if (err == 0 && rc < 0) | ||
2129 | err = rc; | ||
2130 | rc = smk_preset_netlabel(&smack_known_hat); | ||
2131 | if (err == 0 && rc < 0) | ||
2132 | err = rc; | ||
2133 | rc = smk_preset_netlabel(&smack_known_huh); | ||
2134 | if (err == 0 && rc < 0) | ||
2135 | err = rc; | ||
2136 | rc = smk_preset_netlabel(&smack_known_invalid); | ||
2137 | if (err == 0 && rc < 0) | ||
2138 | err = rc; | ||
2139 | rc = smk_preset_netlabel(&smack_known_star); | ||
2140 | if (err == 0 && rc < 0) | ||
2141 | err = rc; | ||
2142 | rc = smk_preset_netlabel(&smack_known_web); | ||
2143 | if (err == 0 && rc < 0) | ||
2144 | err = rc; | ||
2145 | |||
1617 | return err; | 2146 | return err; |
1618 | } | 2147 | } |
1619 | 2148 | ||