smack_lsm.c 83.8 KB
Newer Older
1 2 3 4 5
/*
 *  Simplified MAC Kernel (smack) security module
 *
 *  This file contains the smack hook function implementations.
 *
6
 *  Authors:
7
 *	Casey Schaufler <casey@schaufler-ca.com>
8
 *	Jarkko Sakkinen <ext-jarkko.2.sakkinen@nokia.com>
9 10
 *
 *  Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
11 12
 *  Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
 *                Paul Moore <paul.moore@hp.com>
13
 *  Copyright (C) 2010 Nokia Corporation
14 15 16 17 18 19 20 21 22 23 24 25
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License version 2,
 *      as published by the Free Software Foundation.
 */

#include <linux/xattr.h>
#include <linux/pagemap.h>
#include <linux/mount.h>
#include <linux/stat.h>
#include <linux/kd.h>
#include <asm/ioctls.h>
26
#include <linux/ip.h>
27 28
#include <linux/tcp.h>
#include <linux/udp.h>
29
#include <linux/slab.h>
30 31 32 33
#include <linux/mutex.h>
#include <linux/pipe_fs_i.h>
#include <net/netlabel.h>
#include <net/cipso_ipv4.h>
34
#include <linux/audit.h>
Nick Black's avatar
Nick Black committed
35
#include <linux/magic.h>
36
#include <linux/dcache.h>
37 38
#include "smack.h"

39 40
#define task_security(task)	(task_cred_xxx((task), security))

41 42 43
#define TRANS_TRUE	"TRUE"
#define TRANS_TRUE_SIZE	4

44 45 46 47 48 49 50 51
/**
 * smk_fetch - Fetch the smack label from a file.
 * @ip: a pointer to the inode
 * @dp: a pointer to the dentry
 *
 * Returns a pointer to the master list entry for the Smack label
 * or NULL if there was no label to fetch.
 */
52
static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp)
53 54 55 56 57 58 59
{
	int rc;
	char in[SMK_LABELLEN];

	if (ip->i_op->getxattr == NULL)
		return NULL;

60
	rc = ip->i_op->getxattr(dp, name, in, SMK_LABELLEN);
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
	if (rc < 0)
		return NULL;

	return smk_import(in, rc);
}

/**
 * new_inode_smack - allocate an inode security blob
 * @smack: a pointer to the Smack label to use in the blob
 *
 * Returns the new blob or NULL if there's no memory available
 */
struct inode_smack *new_inode_smack(char *smack)
{
	struct inode_smack *isp;

	isp = kzalloc(sizeof(struct inode_smack), GFP_KERNEL);
	if (isp == NULL)
		return NULL;

	isp->smk_inode = smack;
	isp->smk_flags = 0;
	mutex_init(&isp->smk_lock);

	return isp;
}

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
/**
 * new_task_smack - allocate a task security blob
 * @smack: a pointer to the Smack label to use in the blob
 *
 * Returns the new blob or NULL if there's no memory available
 */
static struct task_smack *new_task_smack(char *task, char *forked, gfp_t gfp)
{
	struct task_smack *tsp;

	tsp = kzalloc(sizeof(struct task_smack), gfp);
	if (tsp == NULL)
		return NULL;

	tsp->smk_task = task;
	tsp->smk_forked = forked;
	INIT_LIST_HEAD(&tsp->smk_rules);
	mutex_init(&tsp->smk_rules_lock);

	return tsp;
}

/**
 * smk_copy_rules - copy a rule set
 * @nhead - new rules header pointer
 * @ohead - old rules header pointer
 *
 * Returns 0 on success, -ENOMEM on error
 */
static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead,
				gfp_t gfp)
{
	struct smack_rule *nrp;
	struct smack_rule *orp;
	int rc = 0;

	INIT_LIST_HEAD(nhead);

	list_for_each_entry_rcu(orp, ohead, list) {
		nrp = kzalloc(sizeof(struct smack_rule), gfp);
		if (nrp == NULL) {
			rc = -ENOMEM;
			break;
		}
		*nrp = *orp;
		list_add_rcu(&nrp->list, nhead);
	}
	return rc;
}

138 139 140 141 142 143
/*
 * LSM hooks.
 * We he, that is fun!
 */

/**
144
 * smack_ptrace_access_check - Smack approval on PTRACE_ATTACH
145
 * @ctp: child task pointer
146
 * @mode: ptrace attachment mode
147 148 149 150 151
 *
 * Returns 0 if access is OK, an error code otherwise
 *
 * Do the capability checks, and require read and write.
 */
152
static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
153 154
{
	int rc;
Etienne Basset's avatar
Etienne Basset committed
155
	struct smk_audit_info ad;
156
	char *tsp;
157

158
	rc = cap_ptrace_access_check(ctp, mode);
159 160 161
	if (rc != 0)
		return rc;

162
	tsp = smk_of_task(task_security(ctp));
Etienne Basset's avatar
Etienne Basset committed
163 164 165
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
	smk_ad_setfield_u_tsk(&ad, ctp);

166
	rc = smk_curacc(tsp, MAY_READWRITE, &ad);
167 168 169 170 171 172 173 174 175 176 177 178 179 180
	return rc;
}

/**
 * smack_ptrace_traceme - Smack approval on PTRACE_TRACEME
 * @ptp: parent task pointer
 *
 * Returns 0 if access is OK, an error code otherwise
 *
 * Do the capability checks, and require read and write.
 */
static int smack_ptrace_traceme(struct task_struct *ptp)
{
	int rc;
Etienne Basset's avatar
Etienne Basset committed
181
	struct smk_audit_info ad;
182
	char *tsp;
183 184 185 186

	rc = cap_ptrace_traceme(ptp);
	if (rc != 0)
		return rc;
187

188
	tsp = smk_of_task(task_security(ptp));
Etienne Basset's avatar
Etienne Basset committed
189 190 191
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
	smk_ad_setfield_u_tsk(&ad, ptp);

192
	rc = smk_curacc(tsp, MAY_READWRITE, &ad);
193 194 195 196 197 198 199 200 201 202 203
	return rc;
}

/**
 * smack_syslog - Smack approval on syslog
 * @type: message type
 *
 * Require that the task has the floor label
 *
 * Returns 0 on success, error code otherwise.
 */
204
static int smack_syslog(int typefrom_file)
205
{
206
	int rc = 0;
207
	char *sp = smk_of_current();
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263

	if (capable(CAP_MAC_OVERRIDE))
		return 0;

	 if (sp != smack_known_floor.smk_known)
		rc = -EACCES;

	return rc;
}


/*
 * Superblock Hooks.
 */

/**
 * smack_sb_alloc_security - allocate a superblock blob
 * @sb: the superblock getting the blob
 *
 * Returns 0 on success or -ENOMEM on error.
 */
static int smack_sb_alloc_security(struct super_block *sb)
{
	struct superblock_smack *sbsp;

	sbsp = kzalloc(sizeof(struct superblock_smack), GFP_KERNEL);

	if (sbsp == NULL)
		return -ENOMEM;

	sbsp->smk_root = smack_known_floor.smk_known;
	sbsp->smk_default = smack_known_floor.smk_known;
	sbsp->smk_floor = smack_known_floor.smk_known;
	sbsp->smk_hat = smack_known_hat.smk_known;
	sbsp->smk_initialized = 0;
	spin_lock_init(&sbsp->smk_sblock);

	sb->s_security = sbsp;

	return 0;
}

/**
 * smack_sb_free_security - free a superblock blob
 * @sb: the superblock getting the blob
 *
 */
static void smack_sb_free_security(struct super_block *sb)
{
	kfree(sb->s_security);
	sb->s_security = NULL;
}

/**
 * smack_sb_copy_data - copy mount options data for processing
 * @orig: where to start
264
 * @smackopts: mount options string
265 266 267 268 269 270
 *
 * Returns 0 on success or -ENOMEM on error.
 *
 * Copy the Smack specific mount options out of the mount
 * options list.
 */
271
static int smack_sb_copy_data(char *orig, char *smackopts)
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
{
	char *cp, *commap, *otheropts, *dp;

	otheropts = (char *)get_zeroed_page(GFP_KERNEL);
	if (otheropts == NULL)
		return -ENOMEM;

	for (cp = orig, commap = orig; commap != NULL; cp = commap + 1) {
		if (strstr(cp, SMK_FSDEFAULT) == cp)
			dp = smackopts;
		else if (strstr(cp, SMK_FSFLOOR) == cp)
			dp = smackopts;
		else if (strstr(cp, SMK_FSHAT) == cp)
			dp = smackopts;
		else if (strstr(cp, SMK_FSROOT) == cp)
			dp = smackopts;
		else
			dp = otheropts;

		commap = strchr(cp, ',');
		if (commap != NULL)
			*commap = '\0';

		if (*dp != '\0')
			strcat(dp, ",");
		strcat(dp, cp);
	}

	strcpy(orig, otheropts);
	free_page((unsigned long)otheropts);

	return 0;
}

/**
 * smack_sb_kern_mount - Smack specific mount processing
 * @sb: the file system superblock
309
 * @flags: the mount flags
310 311 312 313
 * @data: the smack mount options
 *
 * Returns 0 on success, an error code on failure
 */
314
static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
{
	struct dentry *root = sb->s_root;
	struct inode *inode = root->d_inode;
	struct superblock_smack *sp = sb->s_security;
	struct inode_smack *isp;
	char *op;
	char *commap;
	char *nsp;

	spin_lock(&sp->smk_sblock);
	if (sp->smk_initialized != 0) {
		spin_unlock(&sp->smk_sblock);
		return 0;
	}
	sp->smk_initialized = 1;
	spin_unlock(&sp->smk_sblock);

	for (op = data; op != NULL; op = commap) {
		commap = strchr(op, ',');
		if (commap != NULL)
			*commap++ = '\0';

		if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
			op += strlen(SMK_FSHAT);
			nsp = smk_import(op, 0);
			if (nsp != NULL)
				sp->smk_hat = nsp;
		} else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
			op += strlen(SMK_FSFLOOR);
			nsp = smk_import(op, 0);
			if (nsp != NULL)
				sp->smk_floor = nsp;
		} else if (strncmp(op, SMK_FSDEFAULT,
				   strlen(SMK_FSDEFAULT)) == 0) {
			op += strlen(SMK_FSDEFAULT);
			nsp = smk_import(op, 0);
			if (nsp != NULL)
				sp->smk_default = nsp;
		} else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
			op += strlen(SMK_FSROOT);
			nsp = smk_import(op, 0);
			if (nsp != NULL)
				sp->smk_root = nsp;
		}
	}

	/*
	 * Initialize the root inode.
	 */
	isp = inode->i_security;
	if (isp == NULL)
		inode->i_security = new_inode_smack(sp->smk_root);
	else
		isp->smk_inode = sp->smk_root;

	return 0;
}

/**
 * smack_sb_statfs - Smack check on statfs
 * @dentry: identifies the file system in question
 *
 * Returns 0 if current can read the floor of the filesystem,
 * and error code otherwise
 */
static int smack_sb_statfs(struct dentry *dentry)
{
	struct superblock_smack *sbp = dentry->d_sb->s_security;
Etienne Basset's avatar
Etienne Basset committed
383 384 385
	int rc;
	struct smk_audit_info ad;

386
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
Etienne Basset's avatar
Etienne Basset committed
387
	smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
388

Etienne Basset's avatar
Etienne Basset committed
389 390
	rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad);
	return rc;
391 392 393 394 395
}

/**
 * smack_sb_mount - Smack check for mounting
 * @dev_name: unused
396
 * @path: mount point
397 398 399 400 401 402 403
 * @type: unused
 * @flags: unused
 * @data: unused
 *
 * Returns 0 if current can write the floor of the filesystem
 * being mounted on, an error code otherwise.
 */
404
static int smack_sb_mount(char *dev_name, struct path *path,
405 406
			  char *type, unsigned long flags, void *data)
{
407
	struct superblock_smack *sbp = path->mnt->mnt_sb->s_security;
Etienne Basset's avatar
Etienne Basset committed
408
	struct smk_audit_info ad;
409

410
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
Etienne Basset's avatar
Etienne Basset committed
411 412 413
	smk_ad_setfield_u_fs_path(&ad, *path);

	return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
414 415 416 417 418 419 420 421 422 423 424 425 426
}

/**
 * smack_sb_umount - Smack check for unmounting
 * @mnt: file system to unmount
 * @flags: unused
 *
 * Returns 0 if current can write the floor of the filesystem
 * being unmounted, an error code otherwise.
 */
static int smack_sb_umount(struct vfsmount *mnt, int flags)
{
	struct superblock_smack *sbp;
Etienne Basset's avatar
Etienne Basset committed
427
	struct smk_audit_info ad;
428 429 430 431
	struct path path;

	path.dentry = mnt->mnt_root;
	path.mnt = mnt;
432

433
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
434
	smk_ad_setfield_u_fs_path(&ad, path);
435

Etienne Basset's avatar
Etienne Basset committed
436 437
	sbp = mnt->mnt_sb->s_security;
	return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
438 439
}

440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
/*
 * BPRM hooks
 */

static int smack_bprm_set_creds(struct linux_binprm *bprm)
{
	struct task_smack *tsp = bprm->cred->security;
	struct inode_smack *isp;
	struct dentry *dp;
	int rc;

	rc = cap_bprm_set_creds(bprm);
	if (rc != 0)
		return rc;

	if (bprm->cred_prepared)
		return 0;

	if (bprm->file == NULL || bprm->file->f_dentry == NULL)
		return 0;

	dp = bprm->file->f_dentry;

	if (dp->d_inode == NULL)
		return 0;

	isp = dp->d_inode->i_security;

	if (isp->smk_task != NULL)
		tsp->smk_task = isp->smk_task;

	return 0;
}

474 475 476 477 478 479
/*
 * Inode hooks
 */

/**
 * smack_inode_alloc_security - allocate an inode blob
480
 * @inode: the inode in need of a blob
481 482 483 484 485
 *
 * Returns 0 if it gets a blob, -ENOMEM otherwise
 */
static int smack_inode_alloc_security(struct inode *inode)
{
486
	inode->i_security = new_inode_smack(smk_of_current());
487 488 489 490 491 492 493
	if (inode->i_security == NULL)
		return -ENOMEM;
	return 0;
}

/**
 * smack_inode_free_security - free an inode blob
494
 * @inode: the inode with a blob
495 496 497 498 499 500 501 502 503 504 505 506 507
 *
 * Clears the blob pointer in inode
 */
static void smack_inode_free_security(struct inode *inode)
{
	kfree(inode->i_security);
	inode->i_security = NULL;
}

/**
 * smack_inode_init_security - copy out the smack from an inode
 * @inode: the inode
 * @dir: unused
508
 * @qstr: unused
509 510 511 512 513 514 515
 * @name: where to put the attribute name
 * @value: where to put the attribute value
 * @len: where to put the length of the attribute
 *
 * Returns 0 if it all works out, -ENOMEM if there's no memory
 */
static int smack_inode_init_security(struct inode *inode, struct inode *dir,
516 517
				     const struct qstr *qstr, char **name,
				     void **value, size_t *len)
518 519
{
	char *isp = smk_of_inode(inode);
520
	char *dsp = smk_of_inode(dir);
521
	int may;
522 523 524 525 526 527 528 529

	if (name) {
		*name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL);
		if (*name == NULL)
			return -ENOMEM;
	}

	if (value) {
530 531 532
		rcu_read_lock();
		may = smk_access_entry(smk_of_current(), dsp, &smack_rule_list);
		rcu_read_unlock();
533 534 535 536 537 538

		/*
		 * If the access rule allows transmutation and
		 * the directory requests transmutation then
		 * by all means transmute.
		 */
539 540
		if (may > 0 && ((may & MAY_TRANSMUTE) != 0) &&
		    smk_inode_transmutable(dir))
541 542
			isp = dsp;

543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
		*value = kstrdup(isp, GFP_KERNEL);
		if (*value == NULL)
			return -ENOMEM;
	}

	if (len)
		*len = strlen(isp) + 1;

	return 0;
}

/**
 * smack_inode_link - Smack check on link
 * @old_dentry: the existing object
 * @dir: unused
 * @new_dentry: the new object
 *
 * Returns 0 if access is permitted, an error code otherwise
 */
static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
			    struct dentry *new_dentry)
{
	char *isp;
Etienne Basset's avatar
Etienne Basset committed
566 567 568
	struct smk_audit_info ad;
	int rc;

569
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
Etienne Basset's avatar
Etienne Basset committed
570
	smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
571 572

	isp = smk_of_inode(old_dentry->d_inode);
Etienne Basset's avatar
Etienne Basset committed
573
	rc = smk_curacc(isp, MAY_WRITE, &ad);
574 575 576

	if (rc == 0 && new_dentry->d_inode != NULL) {
		isp = smk_of_inode(new_dentry->d_inode);
Etienne Basset's avatar
Etienne Basset committed
577 578
		smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
		rc = smk_curacc(isp, MAY_WRITE, &ad);
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
	}

	return rc;
}

/**
 * smack_inode_unlink - Smack check on inode deletion
 * @dir: containing directory object
 * @dentry: file to unlink
 *
 * Returns 0 if current can write the containing directory
 * and the object, error code otherwise
 */
static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
{
	struct inode *ip = dentry->d_inode;
Etienne Basset's avatar
Etienne Basset committed
595
	struct smk_audit_info ad;
596 597
	int rc;

598
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
Etienne Basset's avatar
Etienne Basset committed
599 600
	smk_ad_setfield_u_fs_path_dentry(&ad, dentry);

601 602 603
	/*
	 * You need write access to the thing you're unlinking
	 */
Etienne Basset's avatar
Etienne Basset committed
604 605
	rc = smk_curacc(smk_of_inode(ip), MAY_WRITE, &ad);
	if (rc == 0) {
606 607 608
		/*
		 * You also need write access to the containing directory
		 */
Etienne Basset's avatar
Etienne Basset committed
609 610 611 612
		smk_ad_setfield_u_fs_path_dentry(&ad, NULL);
		smk_ad_setfield_u_fs_inode(&ad, dir);
		rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
	}
613 614 615 616 617 618 619 620 621 622 623 624 625
	return rc;
}

/**
 * smack_inode_rmdir - Smack check on directory deletion
 * @dir: containing directory object
 * @dentry: directory to unlink
 *
 * Returns 0 if current can write the containing directory
 * and the directory, error code otherwise
 */
static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
{
Etienne Basset's avatar
Etienne Basset committed
626
	struct smk_audit_info ad;
627 628
	int rc;

629
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
Etienne Basset's avatar
Etienne Basset committed
630 631
	smk_ad_setfield_u_fs_path_dentry(&ad, dentry);

632 633 634
	/*
	 * You need write access to the thing you're removing
	 */
Etienne Basset's avatar
Etienne Basset committed
635 636
	rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
	if (rc == 0) {
637 638 639
		/*
		 * You also need write access to the containing directory
		 */
Etienne Basset's avatar
Etienne Basset committed
640 641 642 643
		smk_ad_setfield_u_fs_path_dentry(&ad, NULL);
		smk_ad_setfield_u_fs_inode(&ad, dir);
		rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
	}
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666

	return rc;
}

/**
 * smack_inode_rename - Smack check on rename
 * @old_inode: the old directory
 * @old_dentry: unused
 * @new_inode: the new directory
 * @new_dentry: unused
 *
 * Read and write access is required on both the old and
 * new directories.
 *
 * Returns 0 if access is permitted, an error code otherwise
 */
static int smack_inode_rename(struct inode *old_inode,
			      struct dentry *old_dentry,
			      struct inode *new_inode,
			      struct dentry *new_dentry)
{
	int rc;
	char *isp;
Etienne Basset's avatar
Etienne Basset committed
667 668
	struct smk_audit_info ad;

669
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
Etienne Basset's avatar
Etienne Basset committed
670
	smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
671 672

	isp = smk_of_inode(old_dentry->d_inode);
Etienne Basset's avatar
Etienne Basset committed
673
	rc = smk_curacc(isp, MAY_READWRITE, &ad);
674 675 676

	if (rc == 0 && new_dentry->d_inode != NULL) {
		isp = smk_of_inode(new_dentry->d_inode);
Etienne Basset's avatar
Etienne Basset committed
677 678
		smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
		rc = smk_curacc(isp, MAY_READWRITE, &ad);
679 680 681 682 683 684 685 686 687 688 689 690 691
	}
	return rc;
}

/**
 * smack_inode_permission - Smack version of permission()
 * @inode: the inode in question
 * @mask: the access requested
 *
 * This is the important Smack hook.
 *
 * Returns 0 if access is permitted, -EACCES otherwise
 */
692
static int smack_inode_permission(struct inode *inode, int mask, unsigned flags)
693
{
Etienne Basset's avatar
Etienne Basset committed
694
	struct smk_audit_info ad;
695 696

	mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
697 698 699 700 701
	/*
	 * No permission to check. Existence test. Yup, it's there.
	 */
	if (mask == 0)
		return 0;
702 703 704 705

	/* May be droppable after audit */
	if (flags & IPERM_FLAG_RCU)
		return -ECHILD;
706
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
Etienne Basset's avatar
Etienne Basset committed
707 708
	smk_ad_setfield_u_fs_inode(&ad, inode);
	return smk_curacc(smk_of_inode(inode), mask, &ad);
709 710 711 712 713 714 715 716 717 718 719
}

/**
 * smack_inode_setattr - Smack check for setting attributes
 * @dentry: the object
 * @iattr: for the force flag
 *
 * Returns 0 if access is permitted, an error code otherwise
 */
static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
{
Etienne Basset's avatar
Etienne Basset committed
720
	struct smk_audit_info ad;
721 722 723 724 725
	/*
	 * Need to allow for clearing the setuid bit.
	 */
	if (iattr->ia_valid & ATTR_FORCE)
		return 0;
726
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
Etienne Basset's avatar
Etienne Basset committed
727
	smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
728

Etienne Basset's avatar
Etienne Basset committed
729
	return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
730 731 732 733 734 735 736 737 738 739 740
}

/**
 * smack_inode_getattr - Smack check for getting attributes
 * @mnt: unused
 * @dentry: the object
 *
 * Returns 0 if access is permitted, an error code otherwise
 */
static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
{
Etienne Basset's avatar
Etienne Basset committed
741
	struct smk_audit_info ad;
742 743 744 745
	struct path path;

	path.dentry = dentry;
	path.mnt = mnt;
Etienne Basset's avatar
Etienne Basset committed
746

747
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
748
	smk_ad_setfield_u_fs_path(&ad, path);
Etienne Basset's avatar
Etienne Basset committed
749
	return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
750 751 752 753 754 755 756 757 758 759 760 761 762 763
}

/**
 * smack_inode_setxattr - Smack check for setting xattrs
 * @dentry: the object
 * @name: name of the attribute
 * @value: unused
 * @size: unused
 * @flags: unused
 *
 * This protects the Smack attribute explicitly.
 *
 * Returns 0 if access is permitted, an error code otherwise
 */
764 765
static int smack_inode_setxattr(struct dentry *dentry, const char *name,
				const void *value, size_t size, int flags)
766
{
Etienne Basset's avatar
Etienne Basset committed
767
	struct smk_audit_info ad;
768
	int rc = 0;
769

770 771
	if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
	    strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
772
	    strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
773 774
	    strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
	    strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
775 776
		if (!capable(CAP_MAC_ADMIN))
			rc = -EPERM;
777 778 779 780 781 782
		/*
		 * check label validity here so import wont fail on
		 * post_setxattr
		 */
		if (size == 0 || size >= SMK_LABELLEN ||
		    smk_import(value, size) == NULL)
783
			rc = -EINVAL;
784 785 786 787 788 789
	} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
		if (!capable(CAP_MAC_ADMIN))
			rc = -EPERM;
		if (size != TRANS_TRUE_SIZE ||
		    strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0)
			rc = -EINVAL;
790 791 792
	} else
		rc = cap_inode_setxattr(dentry, name, value, size, flags);

793
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
Etienne Basset's avatar
Etienne Basset committed
794 795
	smk_ad_setfield_u_fs_path_dentry(&ad, dentry);

796
	if (rc == 0)
Etienne Basset's avatar
Etienne Basset committed
797
		rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
798 799

	return rc;
800 801 802 803 804 805 806 807 808 809 810 811 812
}

/**
 * smack_inode_post_setxattr - Apply the Smack update approved above
 * @dentry: object
 * @name: attribute name
 * @value: attribute value
 * @size: attribute size
 * @flags: unused
 *
 * Set the pointer in the inode blob to the entry found
 * in the master label list.
 */
813 814
static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
				      const void *value, size_t size, int flags)
815 816
{
	char *nsp;
817
	struct inode_smack *isp = dentry->d_inode->i_security;
818 819

	if (strcmp(name, XATTR_NAME_SMACK) == 0) {
820
		nsp = smk_import(value, size);
821 822 823 824
		if (nsp != NULL)
			isp->smk_inode = nsp;
		else
			isp->smk_inode = smack_known_invalid.smk_known;
825 826
	} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
		nsp = smk_import(value, size);
827 828 829 830
		if (nsp != NULL)
			isp->smk_task = nsp;
		else
			isp->smk_task = smack_known_invalid.smk_known;
831 832 833 834 835 836
	} else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
		nsp = smk_import(value, size);
		if (nsp != NULL)
			isp->smk_mmap = nsp;
		else
			isp->smk_mmap = smack_known_invalid.smk_known;
837 838
	} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0)
		isp->smk_flags |= SMK_INODE_TRANSMUTE;
839 840 841 842 843 844 845 846 847 848 849

	return;
}

/*
 * smack_inode_getxattr - Smack check on getxattr
 * @dentry: the object
 * @name: unused
 *
 * Returns 0 if access is permitted, an error code otherwise
 */
850
static int smack_inode_getxattr(struct dentry *dentry, const char *name)
851
{
Etienne Basset's avatar
Etienne Basset committed
852 853
	struct smk_audit_info ad;

854
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
Etienne Basset's avatar
Etienne Basset committed
855 856 857
	smk_ad_setfield_u_fs_path_dentry(&ad, dentry);

	return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
858 859 860 861 862 863 864 865 866 867 868
}

/*
 * smack_inode_removexattr - Smack check on removexattr
 * @dentry: the object
 * @name: name of the attribute
 *
 * Removing the Smack attribute requires CAP_MAC_ADMIN
 *
 * Returns 0 if access is permitted, an error code otherwise
 */
869
static int smack_inode_removexattr(struct dentry *dentry, const char *name)
870
{
871
	struct inode_smack *isp;
Etienne Basset's avatar
Etienne Basset committed
872
	struct smk_audit_info ad;
873
	int rc = 0;
874

875 876
	if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
	    strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
877
	    strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
878
	    strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
879 880
	    strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 ||
	    strcmp(name, XATTR_NAME_SMACKMMAP)) {
881 882 883 884 885
		if (!capable(CAP_MAC_ADMIN))
			rc = -EPERM;
	} else
		rc = cap_inode_removexattr(dentry, name);

886
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
Etienne Basset's avatar
Etienne Basset committed
887
	smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
888
	if (rc == 0)
Etienne Basset's avatar
Etienne Basset committed
889
		rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
890

891 892 893
	if (rc == 0) {
		isp = dentry->d_inode->i_security;
		isp->smk_task = NULL;
894
		isp->smk_mmap = NULL;
895 896
	}

897
	return rc;
898 899 900 901 902 903 904
}

/**
 * smack_inode_getsecurity - get smack xattrs
 * @inode: the object
 * @name: attribute name
 * @buffer: where to put the result
905
 * @alloc: unused
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
 *
 * Returns the size of the attribute or an error code
 */
static int smack_inode_getsecurity(const struct inode *inode,
				   const char *name, void **buffer,
				   bool alloc)
{
	struct socket_smack *ssp;
	struct socket *sock;
	struct super_block *sbp;
	struct inode *ip = (struct inode *)inode;
	char *isp;
	int ilen;
	int rc = 0;

	if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
		isp = smk_of_inode(inode);
		ilen = strlen(isp) + 1;
		*buffer = isp;
		return ilen;
	}

	/*
	 * The rest of the Smack xattrs are only on sockets.
	 */
	sbp = ip->i_sb;
	if (sbp->s_magic != SOCKFS_MAGIC)
		return -EOPNOTSUPP;

	sock = SOCKET_I(ip);
936
	if (sock == NULL || sock->sk == NULL)
937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
		return -EOPNOTSUPP;

	ssp = sock->sk->sk_security;

	if (strcmp(name, XATTR_SMACK_IPIN) == 0)
		isp = ssp->smk_in;
	else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
		isp = ssp->smk_out;
	else
		return -EOPNOTSUPP;

	ilen = strlen(isp) + 1;
	if (rc == 0) {
		*buffer = isp;
		rc = ilen;
	}

	return rc;
}


/**
 * smack_inode_listsecurity - list the Smack attributes
 * @inode: the object
 * @buffer: where they go
 * @buffer_size: size of buffer
 *
 * Returns 0 on success, -EINVAL otherwise
 */
static int smack_inode_listsecurity(struct inode *inode, char *buffer,
				    size_t buffer_size)
{
	int len = strlen(XATTR_NAME_SMACK);

	if (buffer != NULL && len <= buffer_size) {
		memcpy(buffer, XATTR_NAME_SMACK, len);
		return len;
	}
	return -EINVAL;
}

978 979 980 981 982 983 984 985 986 987 988 989
/**
 * smack_inode_getsecid - Extract inode's security id
 * @inode: inode to extract the info from
 * @secid: where result will be saved
 */
static void smack_inode_getsecid(const struct inode *inode, u32 *secid)
{
	struct inode_smack *isp = inode->i_security;

	*secid = smack_to_secid(isp->smk_inode);
}

990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
/*
 * File Hooks
 */

/**
 * smack_file_permission - Smack check on file operations
 * @file: unused
 * @mask: unused
 *
 * Returns 0
 *
 * Should access checks be done on each read or write?
 * UNICOS and SELinux say yes.
 * Trusted Solaris, Trusted Irix, and just about everyone else says no.
 *
 * I'll say no for now. Smack does not do the frequent
 * label changing that SELinux does.
 */
static int smack_file_permission(struct file *file, int mask)
{
	return 0;
}

/**
 * smack_file_alloc_security - assign a file security blob
 * @file: the object
 *
 * The security blob for a file is a pointer to the master
 * label list, so no allocation is done.
 *
 * Returns 0
 */
static int smack_file_alloc_security(struct file *file)
{
1024
	file->f_security = smk_of_current();
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
	return 0;
}

/**
 * smack_file_free_security - clear a file security blob
 * @file: the object
 *
 * The security blob for a file is a pointer to the master
 * label list, so no memory is freed.
 */
static void smack_file_free_security(struct file *file)
{
	file->f_security = NULL;
}

/**
 * smack_file_ioctl - Smack check on ioctls
 * @file: the object
 * @cmd: what to do
 * @arg: unused
 *
 * Relies heavily on the correct use of the ioctl command conventions.
 *
 * Returns 0 if allowed, error code otherwise
 */
static int smack_file_ioctl(struct file *file, unsigned int cmd,
			    unsigned long arg)
{
	int rc = 0;
Etienne Basset's avatar
Etienne Basset committed
1054 1055
	struct smk_audit_info ad;

1056
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
Etienne Basset's avatar
Etienne Basset committed
1057
	smk_ad_setfield_u_fs_path(&ad, file->f_path);
1058 1059

	if (_IOC_DIR(cmd) & _IOC_WRITE)
Etienne Basset's avatar
Etienne Basset committed
1060
		rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
1061 1062

	if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ))
Etienne Basset's avatar
Etienne Basset committed
1063
		rc = smk_curacc(file->f_security, MAY_READ, &ad);
1064 1065 1066 1067 1068 1069 1070

	return rc;
}

/**
 * smack_file_lock - Smack check on file locking
 * @file: the object
1071
 * @cmd: unused
1072 1073 1074 1075 1076
 *
 * Returns 0 if current has write access, error code otherwise
 */
static int smack_file_lock(struct file *file, unsigned int cmd)
{
Etienne Basset's avatar
Etienne Basset committed
1077 1078
	struct smk_audit_info ad;

1079
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
Etienne Basset's avatar
Etienne Basset committed
1080 1081
	smk_ad_setfield_u_fs_path_dentry(&ad, file->f_path.dentry);
	return smk_curacc(file->f_security, MAY_WRITE, &ad);
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
}

/**
 * smack_file_fcntl - Smack check on fcntl
 * @file: the object
 * @cmd: what action to check
 * @arg: unused
 *
 * Returns 0 if current has access, error code otherwise
 */
static int smack_file_fcntl(struct file *file, unsigned int cmd,
			    unsigned long arg)
{
Etienne Basset's avatar
Etienne Basset committed
1095
	struct smk_audit_info ad;
1096 1097
	int rc;

1098
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
Etienne Basset's avatar
Etienne Basset committed
1099 1100
	smk_ad_setfield_u_fs_path(&ad, file->f_path);

1101 1102 1103 1104 1105 1106 1107
	switch (cmd) {
	case F_DUPFD:
	case F_GETFD:
	case F_GETFL:
	case F_GETLK:
	case F_GETOWN:
	case F_GETSIG:
Etienne Basset's avatar
Etienne Basset committed
1108
		rc = smk_curacc(file->f_security, MAY_READ, &ad);
1109 1110 1111 1112 1113 1114 1115
		break;
	case F_SETFD:
	case F_SETFL:
	case F_SETLK:
	case F_SETLKW:
	case F_SETOWN:
	case F_SETSIG:
Etienne Basset's avatar
Etienne Basset committed
1116
		rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
1117 1118
		break;
	default:
Etienne Basset's avatar
Etienne Basset committed
1119
		rc = smk_curacc(file->f_security, MAY_READWRITE, &ad);
1120 1121 1122 1123 1124
	}

	return rc;
}

1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
/**
 * smack_file_mmap :
 * Check permissions for a mmap operation.  The @file may be NULL, e.g.
 * if mapping anonymous memory.
 * @file contains the file structure for file to map (may be NULL).
 * @reqprot contains the protection requested by the application.
 * @prot contains the protection that will be applied by the kernel.
 * @flags contains the operational flags.
 * Return 0 if permission is granted.
 */
static int smack_file_mmap(struct file *file,
			   unsigned long reqprot, unsigned long prot,
			   unsigned long flags, unsigned long addr,
			   unsigned long addr_only)
{
	struct smack_rule *srp;
	struct task_smack *tsp;
	char *sp;
	char *msmack;
1144
	char *osmack;
1145 1146
	struct inode_smack *isp;
	struct dentry *dp;
1147 1148 1149
	int may;
	int mmay;
	int tmay;
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
	int rc;

	/* do DAC check on address space usage */
	rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
	if (rc || addr_only)
		return rc;

	if (file == NULL || file->f_dentry == NULL)
		return 0;

	dp = file->f_dentry;

	if (dp->d_inode == NULL)
		return 0;

	isp = dp->d_inode->i_security;
	if (isp->smk_mmap == NULL)
		return 0;
	msmack = isp->smk_mmap;

	tsp = current_security();
	sp = smk_of_current();
	rc = 0;

	rcu_read_lock();
	/*
	 * For each Smack rule associated with the subject
	 * label verify that the SMACK64MMAP also has access
	 * to that rule's object label.
	 *
	 * Because neither of the labels comes
	 * from the networking code it is sufficient
	 * to compare pointers.
	 */
	list_for_each_entry_rcu(srp, &smack_rule_list, list) {
		if (srp->smk_subject != sp)
			continue;
1187 1188

		osmack = srp->smk_object;
1189 1190 1191
		/*
		 * Matching labels always allows access.
		 */
1192
		if (msmack == osmack)
1193
			continue;
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227
		/*
		 * If there is a matching local rule take
		 * that into account as well.
		 */
		may = smk_access_entry(srp->smk_subject, osmack,
					&tsp->smk_rules);
		if (may == -ENOENT)
			may = srp->smk_access;
		else
			may &= srp->smk_access;
		/*
		 * If may is zero the SMACK64MMAP subject can't
		 * possibly have less access.
		 */
		if (may == 0)
			continue;

		/*
		 * Fetch the global list entry.
		 * If there isn't one a SMACK64MMAP subject
		 * can't have as much access as current.
		 */
		mmay = smk_access_entry(msmack, osmack, &smack_rule_list);
		if (mmay == -ENOENT) {
			rc = -EACCES;
			break;
		}
		/*
		 * If there is a local entry it modifies the
		 * potential access, too.
		 */
		tmay = smk_access_entry(msmack, osmack, &tsp->smk_rules);
		if (tmay != -ENOENT)
			mmay &= tmay;
1228

1229 1230 1231 1232 1233
		/*
		 * If there is any access available to current that is
		 * not available to a SMACK64MMAP subject
		 * deny access.
		 */
1234
		if ((may | mmay) != mmay) {
1235
			rc = -EACCES;
1236
			break;
1237
		}
1238 1239 1240 1241 1242 1243 1244
	}

	rcu_read_unlock();

	return rc;
}

1245 1246 1247 1248 1249 1250 1251 1252 1253
/**
 * smack_file_set_fowner - set the file security blob value
 * @file: object in question
 *
 * Returns 0
 * Further research may be required on this one.
 */
static int smack_file_set_fowner(struct file *file)
{
1254
	file->f_security = smk_of_current();
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
	return 0;
}

/**
 * smack_file_send_sigiotask - Smack on sigio
 * @tsk: The target task
 * @fown: the object the signal come from
 * @signum: unused
 *
 * Allow a privileged task to get signals even if it shouldn't
 *
 * Returns 0 if a subject with the object's smack could
 * write to the task, an error code otherwise.
 */
static int smack_file_send_sigiotask(struct task_struct *tsk,
				     struct fown_struct *fown, int signum)
{
	struct file *file;
	int rc;
1274
	char *tsp = smk_of_task(tsk->cred->security);
Etienne Basset's avatar
Etienne Basset committed
1275
	struct smk_audit_info ad;
1276 1277 1278 1279 1280

	/*
	 * struct fown_struct is never outside the context of a struct file
	 */
	file = container_of(fown, struct file, f_owner);
1281

Etienne Basset's avatar
Etienne Basset committed
1282 1283
	/* we don't log here as rc can be overriden */
	rc = smk_access(file->f_security, tsp, MAY_WRITE, NULL);
1284
	if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
Etienne Basset's avatar
Etienne Basset committed
1285 1286 1287 1288 1289
		rc = 0;

	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
	smk_ad_setfield_u_tsk(&ad, tsk);
	smack_log(file->f_security, tsp, MAY_WRITE, rc, &ad);
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301
	return rc;
}

/**
 * smack_file_receive - Smack file receive check
 * @file: the object
 *
 * Returns 0 if current has access, error code otherwise
 */
static int smack_file_receive(struct file *file)
{
	int may = 0;
Etienne Basset's avatar
Etienne Basset committed
1302
	struct smk_audit_info ad;
1303

Etienne Basset's avatar
Etienne Basset committed
1304 1305
	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
	smk_ad_setfield_u_fs_path(&ad, file->f_path);
1306 1307 1308 1309 1310 1311 1312 1313
	/*
	 * This code relies on bitmasks.
	 */
	if (file->f_mode & FMODE_READ)
		may = MAY_READ;
	if (file->f_mode & FMODE_WRITE)
		may |= MAY_WRITE;

Etienne Basset's avatar
Etienne Basset committed
1314
	return smk_curacc(file->f_security, may, &ad);
1315 1316 1317 1318 1319 1320
}

/*
 * Task hooks
 */

1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331
/**
 * smack_cred_alloc_blank - "allocate" blank task-level security credentials
 * @new: the new credentials
 * @gfp: the atomicity of any memory allocations
 *
 * Prepare a blank set of credentials for modification.  This must allocate all
 * the memory the LSM module might require such that cred_transfer() can
 * complete without error.
 */
static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
{
1332 1333 1334 1335
	struct task_smack *tsp;

	tsp = new_task_smack(NULL, NULL, gfp);
	if (tsp == NULL)
1336
		return -ENOMEM;
1337 1338 1339

	cred->security = tsp;

1340 1341 1342 1343
	return 0;
}


1344
/**
1345 1346
 * smack_cred_free - "free" task-level security credentials
 * @cred: the credentials in question
1347 1348
 *
 */
1349
static void smack_cred_free(struct cred *cred)
1350
{
1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365
	struct task_smack *tsp = cred->security;
	struct smack_rule *rp;
	struct list_head *l;
	struct list_head *n;

	if (tsp == NULL)
		return;
	cred->security = NULL;

	list_for_each_safe(l, n, &tsp->smk_rules) {
		rp = list_entry(l, struct smack_rule, list);
		list_del(&rp->list);
		kfree(rp);
	}
	kfree(tsp);
1366 1367
}

1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378
/**
 * smack_cred_prepare - prepare new set of credentials for modification
 * @new: the new credentials
 * @old: the original credentials
 * @gfp: the atomicity of any memory allocations
 *
 * Prepare a new set of credentials for modification.
 */
static int smack_cred_prepare(struct cred *new, const struct cred *old,
			      gfp_t gfp)
{
1379 1380
	struct task_smack *old_tsp = old->security;
	struct task_smack *new_tsp;
1381
	int rc;
1382

1383
	new_tsp = new_task_smack(old_tsp->smk_task, old_tsp->smk_task, gfp);
1384 1385 1386
	if (new_tsp == NULL)
		return -ENOMEM;

1387 1388 1389 1390
	rc = smk_copy_rules(&new_tsp->smk_rules, &old_tsp->smk_rules, gfp);
	if (rc != 0)
		return rc;

1391
	new->security = new_tsp;
1392 1393 1394
	return 0;
}

1395 1396 1397 1398 1399 1400 1401 1402 1403
/**
 * smack_cred_transfer - Transfer the old credentials to the new credentials
 * @new: the new credentials
 * @old: the original credentials
 *
 * Fill in a set of blank credentials from another set of credentials.
 */
static void smack_cred_transfer(struct cred *new, const struct cred *old)
{
1404 1405 1406 1407 1408
	struct task_smack *old_tsp = old->security;
	struct task_smack *new_tsp = new->security;

	new_tsp->smk_task = old_tsp->smk_task;
	new_tsp->smk_forked = old_tsp->smk_task;
1409 1410 1411 1412 1413
	mutex_init(&new_tsp->smk_rules_lock);
	INIT_LIST_HEAD(&new_tsp->smk_rules);


	/* cbs copy rule list */
1414 1415
}

1416 1417
/**
 * smack_kernel_act_as - Set the subjective context in a set of credentials
1418 1419
 * @new: points to the set of credentials to be modified.
 * @secid: specifies the security ID to be set
1420 1421 1422 1423 1424
 *
 * Set the security data for a kernel service.
 */
static int smack_kernel_act_as(struct cred *new, u32 secid)
{
1425
	struct task_smack *new_tsp = new->security;
1426 1427 1428 1429 1430
	char *smack = smack_from_secid(secid);

	if (smack == NULL)
		return -EINVAL;

1431
	new_tsp->smk_task = smack;
1432 1433 1434 1435 1436
	return 0;
}

/**
 * smack_kernel_create_files_as - Set the file creation label in a set of creds
1437 1438
 * @new: points to the set of credentials to be modified
 * @inode: points to the inode to use as a reference
1439 1440 1441 1442 1443 1444 1445 1446
 *
 * Set the file creation context in a set of credentials to the same
 * as the objective context of the specified inode
 */
static int smack_kernel_create_files_as(struct cred *new,
					struct inode *inode)
{
	struct inode_smack *isp = inode->i_security;
1447
	struct task_smack *tsp = new->security;
1448

1449 1450
	tsp->smk_forked = isp->smk_inode;
	tsp->smk_task = isp->smk_inode;
1451 1452 1453
	return 0;
}

Etienne Basset's avatar
Etienne Basset committed
1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466
/**
 * smk_curacc_on_task - helper to log task related access
 * @p: the task object
 * @access : the access requested
 *
 * Return 0 if access is permitted
 */
static int smk_curacc_on_task(struct task_struct *p, int access)
{
	struct smk_audit_info ad;

	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
	smk_ad_setfield_u_tsk(&ad, p);
1467
	return smk_curacc(smk_of_task(task_security(p)), access, &ad);
Etienne Basset's avatar
Etienne Basset committed
1468 1469
}

1470 1471 1472 1473 1474 1475 1476 1477 1478
/**
 * smack_task_setpgid - Smack check on setting pgid
 * @p: the task object
 * @pgid: unused
 *
 * Return 0 if write access is permitted
 */
static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
{
Etienne Basset's avatar
Etienne Basset committed
1479
	return smk_curacc_on_task(p, MAY_WRITE);
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489
}

/**
 * smack_task_getpgid - Smack access check for getpgid
 * @p: the object task
 *
 * Returns 0 if current can read the object task, error code otherwise
 */
static int smack_task_getpgid(struct task_struct *p)
{
Etienne Basset's avatar
Etienne Basset committed
1490
	return smk_curacc_on_task(p, MAY_READ);
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500
}

/**
 * smack_task_getsid - Smack access check for getsid
 * @p: the object task
 *
 * Returns 0 if current can read the object task, error code otherwise
 */
static int smack_task_getsid(struct task_struct *p)
{
Etienne Basset's avatar
Etienne Basset committed
1501
	return smk_curacc_on_task(p, MAY_READ);
1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512
}

/**
 * smack_task_getsecid - get the secid of the task
 * @p: the object task
 * @secid: where to put the result
 *
 * Sets the secid to contain a u32 version of the smack label.
 */
static void smack_task_getsecid(struct task_struct *p, u32 *secid)
{
1513
	*secid = smack_to_secid(smk_of_task(task_security(p)));
1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524
}

/**
 * smack_task_setnice - Smack check on setting nice
 * @p: the task object
 * @nice: unused
 *
 * Return 0 if write access is permitted
 */
static int smack_task_setnice(struct task_struct *p, int nice)
{
1525 1526 1527 1528
	int rc;

	rc = cap_task_setnice(p, nice);
	if (rc == 0)
Etienne Basset's avatar
Etienne Basset committed
1529
		rc = smk_curacc_on_task(p, MAY_WRITE);
1530
	return rc;
1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541
}

/**
 * smack_task_setioprio - Smack check on setting ioprio
 * @p: the task object
 * @ioprio: unused
 *
 * Return 0 if write access is permitted
 */
static int smack_task_setioprio(struct task_struct *p, int ioprio)
{
1542 1543 1544 1545
	int rc;

	rc = cap_task_setioprio(p, ioprio);
	if (rc == 0)
Etienne Basset's avatar
Etienne Basset committed
1546
		rc = smk_curacc_on_task(p, MAY_WRITE);
1547
	return rc;
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557
}

/**
 * smack_task_getioprio - Smack check on reading ioprio
 * @p: the task object
 *
 * Return 0 if read access is permitted
 */
static int smack_task_getioprio(struct task_struct *p)
{
Etienne Basset's avatar
Etienne Basset committed
1558
	return smk_curacc_on_task(p, MAY_READ);
1559 1560 1561 1562 1563 1564 1565 1566 1567 1568
}

/**
 * smack_task_setscheduler - Smack check on setting scheduler
 * @p: the task object
 * @policy: unused
 * @lp: unused
 *
 * Return 0 if read access is permitted
 */
1569
static int smack_task_setscheduler(struct task_struct *p)
1570
{
1571 1572
	int rc;

1573
	rc = cap_task_setscheduler(p);
1574
	if (rc == 0)
Etienne Basset's avatar
Etienne Basset committed
1575
		rc = smk_curacc_on_task(p, MAY_WRITE);
1576
	return rc;
1577 1578 1579 1580 1581 1582 1583 1584 1585 1586
}

/**
 * smack_task_getscheduler - Smack check on reading scheduler
 * @p: the task object
 *
 * Return 0 if read access is permitted
 */
static int smack_task_getscheduler(struct task_struct *p)
{
Etienne Basset's avatar
Etienne Basset committed
1587
	return smk_curacc_on_task(p, MAY_READ);
1588 1589 1590 1591 1592 1593 1594 1595 1596 1597
}

/**
 * smack_task_movememory - Smack check on moving memory
 * @p: the task object
 *
 * Return 0 if write access is permitted
 */
static int smack_task_movememory(struct task_struct *p)
{
Etienne Basset's avatar
Etienne Basset committed
1598
	return smk_curacc_on_task(p, MAY_WRITE);
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615
}

/**
 * smack_task_kill - Smack check on signal delivery
 * @p: the task object
 * @info: unused
 * @sig: unused
 * @secid: identifies the smack to use in lieu of current's
 *
 * Return 0 if write access is permitted
 *
 * The secid behavior is an artifact of an SELinux hack
 * in the USB code. Someday it may go away.
 */
static int smack_task_kill(struct task_struct *p, struct siginfo *info,
			   int sig, u32 secid)
{
Etienne Basset's avatar
Etienne Basset committed
1616 1617 1618 1619
	struct smk_audit_info ad;

	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
	smk_ad_setfield_u_tsk(&ad, p);
1620 1621 1622 1623 1624
	/*
	 * Sending a signal requires that the sender
	 * can write the receiver.
	 */
	if (secid == 0)
1625 1626
		return smk_curacc(smk_of_task(task_security(p)), MAY_WRITE,
				  &ad);