aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack/smackfs.c
diff options
context:
space:
mode:
authorCasey Schaufler <casey@schaufler-ca.com>2011-01-17 11:05:27 -0500
committerCasey Schaufler <casey@schaufler-ca.com>2011-01-17 11:05:27 -0500
commit7898e1f8e9eb1bee88c92d636e0ab93f2cbe31c6 (patch)
treed4aaa367bb42d0ff9d1e4ba227f248b5b9cd7687 /security/smack/smackfs.c
parentaeda4ac3efc29e4d55989abd0a73530453aa69ba (diff)
Subject: [PATCH] Smack: mmap controls for library containment
In the embedded world there are often situations where libraries are updated from a variety of sources, for a variety of reasons, and with any number of security characteristics. These differences might include privilege required for a given library provided interface to function properly, as occurs from time to time in graphics libraries. There are also cases where it is important to limit use of libraries based on the provider of the library and the security aware application may make choices based on that criteria. These issues are addressed by providing an additional Smack label that may optionally be assigned to an object, the SMACK64MMAP attribute. An mmap operation is allowed if there is no such attribute. If there is a SMACK64MMAP attribute the mmap is permitted only if a subject with that label has all of the access permitted a subject with the current task label. Security aware applications may from time to time wish to reduce their "privilege" to avoid accidental use of privilege. One case where this arises is the environment in which multiple sources provide libraries to perform the same functions. An application may know that it should eschew services made available from a particular vendor, or of a particular version. In support of this a secondary list of Smack rules has been added that is local to the task. This list is consulted only in the case where the global list has approved access. It can only further restrict access. Unlike the global last, if no entry is found on the local list access is granted. An application can add entries to its own list by writing to /smack/load-self. The changes appear large as they involve refactoring the list handling to accomodate there being more than one rule list. Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Diffstat (limited to 'security/smack/smackfs.c')
-rw-r--r--security/smack/smackfs.c370
1 files changed, 255 insertions, 115 deletions
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 362d5eda948b..90d1bbaaa6f3 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -43,6 +43,7 @@ enum smk_inos {
43 SMK_NETLBLADDR = 8, /* single label hosts */ 43 SMK_NETLBLADDR = 8, /* single label hosts */
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}; 47};
47 48
48/* 49/*
@@ -135,104 +136,30 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap)
135#define SMK_NETLBLADDRMIN 9 136#define SMK_NETLBLADDRMIN 9
136#define SMK_NETLBLADDRMAX 42 137#define SMK_NETLBLADDRMAX 42
137 138
138/*
139 * Seq_file read operations for /smack/load
140 */
141
142static void *load_seq_start(struct seq_file *s, loff_t *pos)
143{
144 if (*pos == SEQ_READ_FINISHED)
145 return NULL;
146 if (list_empty(&smack_rule_list))
147 return NULL;
148 return smack_rule_list.next;
149}
150
151static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
152{
153 struct list_head *list = v;
154
155 if (list_is_last(list, &smack_rule_list)) {
156 *pos = SEQ_READ_FINISHED;
157 return NULL;
158 }
159 return list->next;
160}
161
162static int load_seq_show(struct seq_file *s, void *v)
163{
164 struct list_head *list = v;
165 struct smack_rule *srp =
166 list_entry(list, struct smack_rule, list);
167
168 seq_printf(s, "%s %s", (char *)srp->smk_subject,
169 (char *)srp->smk_object);
170
171 seq_putc(s, ' ');
172
173 if (srp->smk_access & MAY_READ)
174 seq_putc(s, 'r');
175 if (srp->smk_access & MAY_WRITE)
176 seq_putc(s, 'w');
177 if (srp->smk_access & MAY_EXEC)
178 seq_putc(s, 'x');
179 if (srp->smk_access & MAY_APPEND)
180 seq_putc(s, 'a');
181 if (srp->smk_access & MAY_TRANSMUTE)
182 seq_putc(s, 't');
183 if (srp->smk_access == 0)
184 seq_putc(s, '-');
185
186 seq_putc(s, '\n');
187
188 return 0;
189}
190
191static void load_seq_stop(struct seq_file *s, void *v)
192{
193 /* No-op */
194}
195
196static const struct seq_operations load_seq_ops = {
197 .start = load_seq_start,
198 .next = load_seq_next,
199 .show = load_seq_show,
200 .stop = load_seq_stop,
201};
202
203/**
204 * smk_open_load - open() for /smack/load
205 * @inode: inode structure representing file
206 * @file: "load" file pointer
207 *
208 * For reading, use load_seq_* seq_file reading operations.
209 */
210static int smk_open_load(struct inode *inode, struct file *file)
211{
212 return seq_open(file, &load_seq_ops);
213}
214
215/** 139/**
216 * smk_set_access - add a rule to the rule list 140 * smk_set_access - add a rule to the rule list
217 * @srp: the new rule to add 141 * @srp: the new rule to add
142 * @rule_list: the list of rules
143 * @rule_lock: the rule list lock
218 * 144 *
219 * Looks through the current subject/object/access list for 145 * Looks through the current subject/object/access list for
220 * the subject/object pair and replaces the access that was 146 * the subject/object pair and replaces the access that was
221 * there. If the pair isn't found add it with the specified 147 * there. If the pair isn't found add it with the specified
222 * access. 148 * access.
223 * 149 *
150 * Returns 1 if a rule was found to exist already, 0 if it is new
224 * Returns 0 if nothing goes wrong or -ENOMEM if it fails 151 * Returns 0 if nothing goes wrong or -ENOMEM if it fails
225 * during the allocation of the new pair to add. 152 * during the allocation of the new pair to add.
226 */ 153 */
227static int smk_set_access(struct smack_rule *srp) 154static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
155 struct mutex *rule_lock)
228{ 156{
229 struct smack_rule *sp; 157 struct smack_rule *sp;
230 int ret = 0; 158 int found = 0;
231 int found;
232 mutex_lock(&smack_list_lock);
233 159
234 found = 0; 160 mutex_lock(rule_lock);
235 list_for_each_entry_rcu(sp, &smack_rule_list, list) { 161
162 list_for_each_entry_rcu(sp, rule_list, list) {
236 if (sp->smk_subject == srp->smk_subject && 163 if (sp->smk_subject == srp->smk_subject &&
237 sp->smk_object == srp->smk_object) { 164 sp->smk_object == srp->smk_object) {
238 found = 1; 165 found = 1;
@@ -241,19 +168,21 @@ static int smk_set_access(struct smack_rule *srp)
241 } 168 }
242 } 169 }
243 if (found == 0) 170 if (found == 0)
244 list_add_rcu(&srp->list, &smack_rule_list); 171 list_add_rcu(&srp->list, rule_list);
245 172
246 mutex_unlock(&smack_list_lock); 173 mutex_unlock(rule_lock);
247 174
248 return ret; 175 return found;
249} 176}
250 177
251/** 178/**
252 * smk_write_load - write() for /smack/load 179 * smk_write_load_list - write() for any /smack/load
253 * @file: file pointer, not actually used 180 * @file: file pointer, not actually used
254 * @buf: where to get the data from 181 * @buf: where to get the data from
255 * @count: bytes sent 182 * @count: bytes sent
256 * @ppos: where to start - must be 0 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
257 * 186 *
258 * Get one smack access rule from above. 187 * Get one smack access rule from above.
259 * The format is exactly: 188 * The format is exactly:
@@ -263,21 +192,19 @@ static int smk_set_access(struct smack_rule *srp)
263 * 192 *
264 * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes. 193 * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes.
265 */ 194 */
266static ssize_t smk_write_load(struct file *file, const char __user *buf, 195static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
267 size_t count, loff_t *ppos) 196 size_t count, loff_t *ppos,
197 struct list_head *rule_list,
198 struct mutex *rule_lock)
268{ 199{
269 struct smack_rule *rule; 200 struct smack_rule *rule;
270 char *data; 201 char *data;
271 int rc = -EINVAL; 202 int rc = -EINVAL;
272 203
273 /* 204 /*
274 * Must have privilege.
275 * No partial writes. 205 * No partial writes.
276 * Enough data must be present. 206 * Enough data must be present.
277 */ 207 */
278 if (!capable(CAP_MAC_ADMIN))
279 return -EPERM;
280
281 if (*ppos != 0) 208 if (*ppos != 0)
282 return -EINVAL; 209 return -EINVAL;
283 /* 210 /*
@@ -372,11 +299,13 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
372 goto out_free_rule; 299 goto out_free_rule;
373 } 300 }
374 301
375 rc = smk_set_access(rule); 302 rc = count;
376 303 /*
377 if (!rc) 304 * smk_set_access returns true if there was already a rule
378 rc = count; 305 * for the subject/object pair, and false if it was new.
379 goto out; 306 */
307 if (!smk_set_access(rule, rule_list, rule_lock))
308 goto out;
380 309
381out_free_rule: 310out_free_rule:
382 kfree(rule); 311 kfree(rule);
@@ -385,6 +314,108 @@ out:
385 return rc; 314 return rc;
386} 315}
387 316
317
318/*
319 * Seq_file read operations for /smack/load
320 */
321
322static void *load_seq_start(struct seq_file *s, loff_t *pos)
323{
324 if (*pos == SEQ_READ_FINISHED)
325 return NULL;
326 if (list_empty(&smack_rule_list))
327 return NULL;
328 return smack_rule_list.next;
329}
330
331static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
332{
333 struct list_head *list = v;
334
335 if (list_is_last(list, &smack_rule_list)) {
336 *pos = SEQ_READ_FINISHED;
337 return NULL;
338 }
339 return list->next;
340}
341
342static int load_seq_show(struct seq_file *s, void *v)
343{
344 struct list_head *list = v;
345 struct smack_rule *srp =
346 list_entry(list, struct smack_rule, list);
347
348 seq_printf(s, "%s %s", (char *)srp->smk_subject,
349 (char *)srp->smk_object);
350
351 seq_putc(s, ' ');
352
353 if (srp->smk_access & MAY_READ)
354 seq_putc(s, 'r');
355 if (srp->smk_access & MAY_WRITE)
356 seq_putc(s, 'w');
357 if (srp->smk_access & MAY_EXEC)
358 seq_putc(s, 'x');
359 if (srp->smk_access & MAY_APPEND)
360 seq_putc(s, 'a');
361 if (srp->smk_access & MAY_TRANSMUTE)
362 seq_putc(s, 't');
363 if (srp->smk_access == 0)
364 seq_putc(s, '-');
365
366 seq_putc(s, '\n');
367
368 return 0;
369}
370
371static void load_seq_stop(struct seq_file *s, void *v)
372{
373 /* No-op */
374}
375
376static const struct seq_operations load_seq_ops = {
377 .start = load_seq_start,
378 .next = load_seq_next,
379 .show = load_seq_show,
380 .stop = load_seq_stop,
381};
382
383/**
384 * smk_open_load - open() for /smack/load
385 * @inode: inode structure representing file
386 * @file: "load" file pointer
387 *
388 * For reading, use load_seq_* seq_file reading operations.
389 */
390static int smk_open_load(struct inode *inode, struct file *file)
391{
392 return seq_open(file, &load_seq_ops);
393}
394
395/**
396 * smk_write_load - write() for /smack/load
397 * @file: file pointer, not actually used
398 * @buf: where to get the data from
399 * @count: bytes sent
400 * @ppos: where to start - must be 0
401 *
402 */
403static ssize_t smk_write_load(struct file *file, const char __user *buf,
404 size_t count, loff_t *ppos)
405{
406
407 /*
408 * Must have privilege.
409 * No partial writes.
410 * Enough data must be present.
411 */
412 if (!capable(CAP_MAC_ADMIN))
413 return -EPERM;
414
415 return smk_write_load_list(file, buf, count, ppos, &smack_rule_list,
416 &smack_list_lock);
417}
418
388static const struct file_operations smk_load_ops = { 419static const struct file_operations smk_load_ops = {
389 .open = smk_open_load, 420 .open = smk_open_load,
390 .read = seq_read, 421 .read = seq_read,
@@ -1288,6 +1319,112 @@ static const struct file_operations smk_logging_ops = {
1288 .write = smk_write_logging, 1319 .write = smk_write_logging,
1289 .llseek = default_llseek, 1320 .llseek = default_llseek,
1290}; 1321};
1322
1323/*
1324 * Seq_file read operations for /smack/load-self
1325 */
1326
1327static void *load_self_seq_start(struct seq_file *s, loff_t *pos)
1328{
1329 struct task_smack *tsp = current_security();
1330
1331 if (*pos == SEQ_READ_FINISHED)
1332 return NULL;
1333 if (list_empty(&tsp->smk_rules))
1334 return NULL;
1335 return tsp->smk_rules.next;
1336}
1337
1338static void *load_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
1339{
1340 struct task_smack *tsp = current_security();
1341 struct list_head *list = v;
1342
1343 if (list_is_last(list, &tsp->smk_rules)) {
1344 *pos = SEQ_READ_FINISHED;
1345 return NULL;
1346 }
1347 return list->next;
1348}
1349
1350static int load_self_seq_show(struct seq_file *s, void *v)
1351{
1352 struct list_head *list = v;
1353 struct smack_rule *srp =
1354 list_entry(list, struct smack_rule, list);
1355
1356 seq_printf(s, "%s %s", (char *)srp->smk_subject,
1357 (char *)srp->smk_object);
1358
1359 seq_putc(s, ' ');
1360
1361 if (srp->smk_access & MAY_READ)
1362 seq_putc(s, 'r');
1363 if (srp->smk_access & MAY_WRITE)
1364 seq_putc(s, 'w');
1365 if (srp->smk_access & MAY_EXEC)
1366 seq_putc(s, 'x');
1367 if (srp->smk_access & MAY_APPEND)
1368 seq_putc(s, 'a');
1369 if (srp->smk_access & MAY_TRANSMUTE)
1370 seq_putc(s, 't');
1371 if (srp->smk_access == 0)
1372 seq_putc(s, '-');
1373
1374 seq_putc(s, '\n');
1375
1376 return 0;
1377}
1378
1379static void load_self_seq_stop(struct seq_file *s, void *v)
1380{
1381 /* No-op */
1382}
1383
1384static const struct seq_operations load_self_seq_ops = {
1385 .start = load_self_seq_start,
1386 .next = load_self_seq_next,
1387 .show = load_self_seq_show,
1388 .stop = load_self_seq_stop,
1389};
1390
1391
1392/**
1393 * smk_open_load_self - open() for /smack/load-self
1394 * @inode: inode structure representing file
1395 * @file: "load" file pointer
1396 *
1397 * For reading, use load_seq_* seq_file reading operations.
1398 */
1399static int smk_open_load_self(struct inode *inode, struct file *file)
1400{
1401 return seq_open(file, &load_self_seq_ops);
1402}
1403
1404/**
1405 * smk_write_load_self - write() for /smack/load-self
1406 * @file: file pointer, not actually used
1407 * @buf: where to get the data from
1408 * @count: bytes sent
1409 * @ppos: where to start - must be 0
1410 *
1411 */
1412static ssize_t smk_write_load_self(struct file *file, const char __user *buf,
1413 size_t count, loff_t *ppos)
1414{
1415 struct task_smack *tsp = current_security();
1416
1417 return smk_write_load_list(file, buf, count, ppos, &tsp->smk_rules,
1418 &tsp->smk_rules_lock);
1419}
1420
1421static const struct file_operations smk_load_self_ops = {
1422 .open = smk_open_load_self,
1423 .read = seq_read,
1424 .llseek = seq_lseek,
1425 .write = smk_write_load_self,
1426 .release = seq_release,
1427};
1291/** 1428/**
1292 * smk_fill_super - fill the /smackfs superblock 1429 * smk_fill_super - fill the /smackfs superblock
1293 * @sb: the empty superblock 1430 * @sb: the empty superblock
@@ -1304,23 +1441,26 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
1304 struct inode *root_inode; 1441 struct inode *root_inode;
1305 1442
1306 static struct tree_descr smack_files[] = { 1443 static struct tree_descr smack_files[] = {
1307 [SMK_LOAD] = 1444 [SMK_LOAD] = {
1308 {"load", &smk_load_ops, S_IRUGO|S_IWUSR}, 1445 "load", &smk_load_ops, S_IRUGO|S_IWUSR},
1309 [SMK_CIPSO] = 1446 [SMK_CIPSO] = {
1310 {"cipso", &smk_cipso_ops, S_IRUGO|S_IWUSR}, 1447 "cipso", &smk_cipso_ops, S_IRUGO|S_IWUSR},
1311 [SMK_DOI] = 1448 [SMK_DOI] = {
1312 {"doi", &smk_doi_ops, S_IRUGO|S_IWUSR}, 1449 "doi", &smk_doi_ops, S_IRUGO|S_IWUSR},
1313 [SMK_DIRECT] = 1450 [SMK_DIRECT] = {
1314 {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR}, 1451 "direct", &smk_direct_ops, S_IRUGO|S_IWUSR},
1315 [SMK_AMBIENT] = 1452 [SMK_AMBIENT] = {
1316 {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, 1453 "ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
1317 [SMK_NETLBLADDR] = 1454 [SMK_NETLBLADDR] = {
1318 {"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR}, 1455 "netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR},
1319 [SMK_ONLYCAP] = 1456 [SMK_ONLYCAP] = {
1320 {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, 1457 "onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
1321 [SMK_LOGGING] = 1458 [SMK_LOGGING] = {
1322 {"logging", &smk_logging_ops, S_IRUGO|S_IWUSR}, 1459 "logging", &smk_logging_ops, S_IRUGO|S_IWUSR},
1323 /* last one */ {""} 1460 [SMK_LOAD_SELF] = {
1461 "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO},
1462 /* last one */
1463 {""}
1324 }; 1464 };
1325 1465
1326 rc = simple_fill_super(sb, SMACK_MAGIC, smack_files); 1466 rc = simple_fill_super(sb, SMACK_MAGIC, smack_files);