Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 66867818 authored by Lukasz Pawelczyk's avatar Lukasz Pawelczyk Committed by Casey Schaufler
Browse files

Smack: adds smackfs/ptrace interface



This allows to limit ptrace beyond the regular smack access rules.
It adds a smackfs/ptrace interface that allows smack to be configured
to require equal smack labels for PTRACE_MODE_ATTACH access.
See the changes in Documentation/security/Smack.txt below for details.

Signed-off-by: default avatarLukasz Pawelczyk <l.pawelczyk@partner.samsung.com>
Signed-off-by: default avatarRafal Krypa <r.krypa@samsung.com>
parent 5663884c
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -204,6 +204,16 @@ onlycap
	these capabilities are effective at for processes with any
	label. The value is set by writing the desired label to the
	file or cleared by writing "-" to the file.
ptrace
	This is used to define the current ptrace policy
	0 - default: this is the policy that relies on smack access rules.
	    For the PTRACE_READ a subject needs to have a read access on
	    object. For the PTRACE_ATTACH a read-write access is required.
	1 - exact: this is the policy that limits PTRACE_ATTACH. Attach is
	    only allowed when subject's and object's labels are equal.
	    PTRACE_READ is not affected. Can be overriden with CAP_SYS_PTRACE.
	2 - draconian: this policy behaves like the 'exact' above with an
	    exception that it can't be overriden with CAP_SYS_PTRACE.
revoke-subject
	Writing a Smack label here sets the access to '-' for all access
	rules with that subject label.
+9 −0
Original line number Diff line number Diff line
@@ -176,6 +176,14 @@ struct smk_port_label {
 */
#define SMACK_CIPSO_MAXCATNUM           184     /* 23 * 8 */

/*
 * Ptrace rules
 */
#define SMACK_PTRACE_DEFAULT	0
#define SMACK_PTRACE_EXACT	1
#define SMACK_PTRACE_DRACONIAN	2
#define SMACK_PTRACE_MAX	SMACK_PTRACE_DRACONIAN

/*
 * Flags for untraditional access modes.
 * It shouldn't be necessary to avoid conflicts with definitions
@@ -245,6 +253,7 @@ extern struct smack_known *smack_net_ambient;
extern struct smack_known *smack_onlycap;
extern struct smack_known *smack_syslog_label;
extern const char *smack_cipso_option;
extern int smack_ptrace_rule;

extern struct smack_known smack_known_floor;
extern struct smack_known smack_known_hat;
+4 −1
Original line number Diff line number Diff line
@@ -304,6 +304,9 @@ static void smack_log_callback(struct audit_buffer *ab, void *a)
	audit_log_untrustedstring(ab, sad->subject);
	audit_log_format(ab, " object=");
	audit_log_untrustedstring(ab, sad->object);
	if (sad->request[0] == '\0')
		audit_log_format(ab, " labels_differ");
	else
		audit_log_format(ab, " requested=%s", sad->request);
}

+21 −1
Original line number Diff line number Diff line
@@ -178,7 +178,8 @@ static inline unsigned int smk_ptrace_mode(unsigned int mode)
/**
 * smk_ptrace_rule_check - helper for ptrace access
 * @tracer: tracer process
 * @tracee_label: label of the process that's about to be traced
 * @tracee_label: label of the process that's about to be traced,
 *                the pointer must originate from smack structures
 * @mode: ptrace attachment mode (PTRACE_MODE_*)
 * @func: name of the function that called us, used for audit
 *
@@ -201,6 +202,25 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label,
	tsp = task_security(tracer);
	skp = smk_of_task(tsp);

	if ((mode & PTRACE_MODE_ATTACH) &&
	    (smack_ptrace_rule == SMACK_PTRACE_EXACT ||
	     smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) {
		if (skp->smk_known == tracee_label)
			rc = 0;
		else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)
			rc = -EACCES;
		else if (capable(CAP_SYS_PTRACE))
			rc = 0;
		else
			rc = -EACCES;

		if (saip)
			smack_log(skp->smk_known, tracee_label, 0, rc, saip);

		return rc;
	}

	/* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */
	rc = smk_tskacc(tsp, tracee_label, smk_ptrace_mode(mode), saip);
	return rc;
}
+74 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ enum smk_inos {
	SMK_REVOKE_SUBJ	= 18,	/* set rules with subject label to '-' */
	SMK_CHANGE_RULE	= 19,	/* change or add rules (long labels) */
	SMK_SYSLOG	= 20,	/* change syslog label) */
	SMK_PTRACE	= 21,	/* set ptrace rule */
};

/*
@@ -100,6 +101,15 @@ struct smack_known *smack_onlycap;
 */
struct smack_known *smack_syslog_label;

/*
 * Ptrace current rule
 * SMACK_PTRACE_DEFAULT    regular smack ptrace rules (/proc based)
 * SMACK_PTRACE_EXACT      labels must match, but can be overriden with
 *			   CAP_SYS_PTRACE
 * SMACK_PTRACE_DRACONIAN  lables must match, CAP_SYS_PTRACE has no effect
 */
int smack_ptrace_rule = SMACK_PTRACE_DEFAULT;

/*
 * Certain IP addresses may be designated as single label hosts.
 * Packets are sent there unlabeled, but only from tasks that
@@ -2243,6 +2253,68 @@ static const struct file_operations smk_syslog_ops = {
};


/**
 * smk_read_ptrace - read() for /smack/ptrace
 * @filp: file pointer, not actually used
 * @buf: where to put the result
 * @count: maximum to send along
 * @ppos: where to start
 *
 * Returns number of bytes read or error code, as appropriate
 */
static ssize_t smk_read_ptrace(struct file *filp, char __user *buf,
			       size_t count, loff_t *ppos)
{
	char temp[32];
	ssize_t rc;

	if (*ppos != 0)
		return 0;

	sprintf(temp, "%d\n", smack_ptrace_rule);
	rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
	return rc;
}

/**
 * smk_write_ptrace - write() for /smack/ptrace
 * @file: file pointer
 * @buf: data from user space
 * @count: bytes sent
 * @ppos: where to start - must be 0
 */
static ssize_t smk_write_ptrace(struct file *file, const char __user *buf,
				size_t count, loff_t *ppos)
{
	char temp[32];
	int i;

	if (!smack_privileged(CAP_MAC_ADMIN))
		return -EPERM;

	if (*ppos != 0 || count >= sizeof(temp) || count == 0)
		return -EINVAL;

	if (copy_from_user(temp, buf, count) != 0)
		return -EFAULT;

	temp[count] = '\0';

	if (sscanf(temp, "%d", &i) != 1)
		return -EINVAL;
	if (i < SMACK_PTRACE_DEFAULT || i > SMACK_PTRACE_MAX)
		return -EINVAL;
	smack_ptrace_rule = i;

	return count;
}

static const struct file_operations smk_ptrace_ops = {
	.write		= smk_write_ptrace,
	.read		= smk_read_ptrace,
	.llseek		= default_llseek,
};

/**
 * smk_fill_super - fill the smackfs superblock
 * @sb: the empty superblock
@@ -2296,6 +2368,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
			"change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR},
		[SMK_SYSLOG] = {
			"syslog", &smk_syslog_ops, S_IRUGO|S_IWUSR},
		[SMK_PTRACE] = {
			"ptrace", &smk_ptrace_ops, S_IRUGO|S_IWUSR},
		/* last one */
			{""}
	};