From 94877ed37973a6d6c9a558231c878e59f054010f Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 11 Mar 2014 17:07:06 +0100 Subject: [PATCH] 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. Change-Id: I5459ff414e96dde0430ed8febd92c361c9dc1d81 Signed-off-by: Lukasz Pawelczyk Signed-off-by: Rafal Krypa --- security/smack/smack.h | 9 ++++++ security/smack/smack_lsm.c | 22 +++++++++++++- security/smack/smackfs.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/security/smack/smack.h b/security/smack/smack.h index b9dfc4e..fade085 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -177,6 +177,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 * in fs.h, but do so anyway. @@ -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; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index dd94aae..efd1950 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -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; } diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index ee52fcf..32b2488 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -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 */ }; /* @@ -101,6 +102,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 * can write to the specified label. @@ -2244,6 +2254,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 * @data: unused @@ -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 */ {""} }; -- 2.7.4