aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack/smackfs.c
diff options
context:
space:
mode:
authorJarkko Sakkinen <jarkko.sakkinen@intel.com>2011-09-08 03:12:01 -0400
committerCasey Schaufler <cschaufler@cschaufler-intel.(none)>2011-10-12 17:21:32 -0400
commit828716c28fe4aa232ea280ea8ed6fb103eefb6ac (patch)
treef75377cf3e770a9a67feb64fb8bef867735a975b /security/smack/smackfs.c
parent545a7260343bbaf11c7f1a4b8c3d9660bb9266e5 (diff)
Smack: check permissions from user space (v2)
Adds a new file into SmackFS called 'access'. Wanted Smack permission is written into /smack/access. After that result can be read from the opened file. If access applies result contains 1 and otherwise 0. File access is protected from race conditions by using simple_transaction_get()/set() API. Fixes from the previous version: - Removed smack.h changes, refactoring left-over from previous version. - Removed #include <linux/smack.h>, refactoring left-over from previous version. Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@intel.com> Signed-off-by: Casey Schaufler <cschaufler@cschaufler-intel.(none)>
Diffstat (limited to 'security/smack/smackfs.c')
-rw-r--r--security/smack/smackfs.c180
1 files changed, 117 insertions, 63 deletions
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index f93460156dce..f4c28eeba1b1 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -44,6 +44,7 @@ enum smk_inos {
44 SMK_ONLYCAP = 9, /* the only "capable" label */ 44 SMK_ONLYCAP = 9, /* the only "capable" label */
45 SMK_LOGGING = 10, /* logging */ 45 SMK_LOGGING = 10, /* logging */
46 SMK_LOAD_SELF = 11, /* task specific rules */ 46 SMK_LOAD_SELF = 11, /* task specific rules */
47 SMK_ACCESSES = 12, /* access policy */
47}; 48};
48 49
49/* 50/*
@@ -176,71 +177,19 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
176} 177}
177 178
178/** 179/**
179 * smk_write_load_list - write() for any /smack/load 180 * smk_parse_rule - parse subject, object and access type
180 * @file: file pointer, not actually used 181 * @data: string to be parsed whose size is SMK_LOADLEN
181 * @buf: where to get the data from 182 * @rule: parsed entities are stored in here
182 * @count: bytes sent
183 * @ppos: where to start - must be 0
184 * @rule_list: the list of rules to write to
185 * @rule_lock: lock for the rule list
186 *
187 * Get one smack access rule from above.
188 * The format is exactly:
189 * char subject[SMK_LABELLEN]
190 * char object[SMK_LABELLEN]
191 * char access[SMK_ACCESSLEN]
192 *
193 * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes.
194 */ 183 */
195static ssize_t smk_write_load_list(struct file *file, const char __user *buf, 184static int smk_parse_rule(const char *data, struct smack_rule *rule)
196 size_t count, loff_t *ppos,
197 struct list_head *rule_list,
198 struct mutex *rule_lock)
199{ 185{
200 struct smack_rule *rule;
201 char *data;
202 int rc = -EINVAL;
203
204 /*
205 * No partial writes.
206 * Enough data must be present.
207 */
208 if (*ppos != 0)
209 return -EINVAL;
210 /*
211 * Minor hack for backward compatibility
212 */
213 if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN)
214 return -EINVAL;
215
216 data = kzalloc(SMK_LOADLEN, GFP_KERNEL);
217 if (data == NULL)
218 return -ENOMEM;
219
220 if (copy_from_user(data, buf, count) != 0) {
221 rc = -EFAULT;
222 goto out;
223 }
224
225 /*
226 * More on the minor hack for backward compatibility
227 */
228 if (count == (SMK_OLOADLEN))
229 data[SMK_OLOADLEN] = '-';
230
231 rule = kzalloc(sizeof(*rule), GFP_KERNEL);
232 if (rule == NULL) {
233 rc = -ENOMEM;
234 goto out;
235 }
236
237 rule->smk_subject = smk_import(data, 0); 186 rule->smk_subject = smk_import(data, 0);
238 if (rule->smk_subject == NULL) 187 if (rule->smk_subject == NULL)
239 goto out_free_rule; 188 return -1;
240 189
241 rule->smk_object = smk_import(data + SMK_LABELLEN, 0); 190 rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
242 if (rule->smk_object == NULL) 191 if (rule->smk_object == NULL)
243 goto out_free_rule; 192 return -1;
244 193
245 rule->smk_access = 0; 194 rule->smk_access = 0;
246 195
@@ -252,7 +201,7 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
252 rule->smk_access |= MAY_READ; 201 rule->smk_access |= MAY_READ;
253 break; 202 break;
254 default: 203 default:
255 goto out_free_rule; 204 return -1;
256 } 205 }
257 206
258 switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { 207 switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
@@ -263,7 +212,7 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
263 rule->smk_access |= MAY_WRITE; 212 rule->smk_access |= MAY_WRITE;
264 break; 213 break;
265 default: 214 default:
266 goto out_free_rule; 215 return -1;
267 } 216 }
268 217
269 switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { 218 switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
@@ -274,7 +223,7 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
274 rule->smk_access |= MAY_EXEC; 223 rule->smk_access |= MAY_EXEC;
275 break; 224 break;
276 default: 225 default:
277 goto out_free_rule; 226 return -1;
278 } 227 }
279 228
280 switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { 229 switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
@@ -285,7 +234,7 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
285 rule->smk_access |= MAY_APPEND; 234 rule->smk_access |= MAY_APPEND;
286 break; 235 break;
287 default: 236 default:
288 goto out_free_rule; 237 return -1;
289 } 238 }
290 239
291 switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) { 240 switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) {
@@ -296,9 +245,74 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
296 rule->smk_access |= MAY_TRANSMUTE; 245 rule->smk_access |= MAY_TRANSMUTE;
297 break; 246 break;
298 default: 247 default:
299 goto out_free_rule; 248 return -1;
300 } 249 }
301 250
251 return 0;
252}
253
254/**
255 * smk_write_load_list - write() for any /smack/load
256 * @file: file pointer, not actually used
257 * @buf: where to get the data from
258 * @count: bytes sent
259 * @ppos: where to start - must be 0
260 * @rule_list: the list of rules to write to
261 * @rule_lock: lock for the rule list
262 *
263 * Get one smack access rule from above.
264 * The format is exactly:
265 * char subject[SMK_LABELLEN]
266 * char object[SMK_LABELLEN]
267 * char access[SMK_ACCESSLEN]
268 *
269 * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes.
270 */
271static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
272 size_t count, loff_t *ppos,
273 struct list_head *rule_list,
274 struct mutex *rule_lock)
275{
276 struct smack_rule *rule;
277 char *data;
278 int rc = -EINVAL;
279
280 /*
281 * No partial writes.
282 * Enough data must be present.
283 */
284 if (*ppos != 0)
285 return -EINVAL;
286 /*
287 * Minor hack for backward compatibility
288 */
289 if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN)
290 return -EINVAL;
291
292 data = kzalloc(SMK_LOADLEN, GFP_KERNEL);
293 if (data == NULL)
294 return -ENOMEM;
295
296 if (copy_from_user(data, buf, count) != 0) {
297 rc = -EFAULT;
298 goto out;
299 }
300
301 /*
302 * More on the minor hack for backward compatibility
303 */
304 if (count == (SMK_OLOADLEN))
305 data[SMK_OLOADLEN] = '-';
306
307 rule = kzalloc(sizeof(*rule), GFP_KERNEL);
308 if (rule == NULL) {
309 rc = -ENOMEM;
310 goto out;
311 }
312
313 if (smk_parse_rule(data, rule))
314 goto out_free_rule;
315
302 rc = count; 316 rc = count;
303 /* 317 /*
304 * smk_set_access returns true if there was already a rule 318 * smk_set_access returns true if there was already a rule
@@ -1425,6 +1439,44 @@ static const struct file_operations smk_load_self_ops = {
1425 .write = smk_write_load_self, 1439 .write = smk_write_load_self,
1426 .release = seq_release, 1440 .release = seq_release,
1427}; 1441};
1442
1443/**
1444 * smk_write_access - handle access check transaction
1445 * @file: file pointer
1446 * @buf: data from user space
1447 * @count: bytes sent
1448 * @ppos: where to start - must be 0
1449 */
1450static ssize_t smk_write_access(struct file *file, const char __user *buf,
1451 size_t count, loff_t *ppos)
1452{
1453 struct smack_rule rule;
1454 char *data;
1455
1456 if (!capable(CAP_MAC_ADMIN))
1457 return -EPERM;
1458
1459 data = simple_transaction_get(file, buf, count);
1460 if (IS_ERR(data))
1461 return PTR_ERR(data);
1462
1463 if (count < SMK_LOADLEN || smk_parse_rule(data, &rule))
1464 return -EINVAL;
1465
1466 data[0] = smk_access(rule.smk_subject, rule.smk_object,
1467 rule.smk_access, NULL) == 0;
1468
1469 simple_transaction_set(file, 1);
1470 return SMK_LOADLEN;
1471}
1472
1473static const struct file_operations smk_access_ops = {
1474 .write = smk_write_access,
1475 .read = simple_transaction_read,
1476 .release = simple_transaction_release,
1477 .llseek = generic_file_llseek,
1478};
1479
1428/** 1480/**
1429 * smk_fill_super - fill the /smackfs superblock 1481 * smk_fill_super - fill the /smackfs superblock
1430 * @sb: the empty superblock 1482 * @sb: the empty superblock
@@ -1459,6 +1511,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
1459 "logging", &smk_logging_ops, S_IRUGO|S_IWUSR}, 1511 "logging", &smk_logging_ops, S_IRUGO|S_IWUSR},
1460 [SMK_LOAD_SELF] = { 1512 [SMK_LOAD_SELF] = {
1461 "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO}, 1513 "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO},
1514 [SMK_ACCESSES] = {
1515 "access", &smk_access_ops, S_IRUGO|S_IWUSR},
1462 /* last one */ 1516 /* last one */
1463 {""} 1517 {""}
1464 }; 1518 };