From 668678185247303450e60df14569f94cf5775fea Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Tue, 11 Mar 2014 17:07:06 +0100 Subject: 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: Lukasz Pawelczyk Signed-off-by: Rafal Krypa --- security/smack/smack.h | 9 ++++++ security/smack/smack_access.c | 5 ++- security/smack/smack_lsm.c | 22 ++++++++++++- security/smack/smackfs.c | 74 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 2 deletions(-) (limited to 'security/smack') diff --git a/security/smack/smack.h b/security/smack/smack.h index b9dfc4e1d3e0..fade085b1128 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -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; diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index f161debed02b..c062e9467b62 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -304,7 +304,10 @@ 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); - audit_log_format(ab, " requested=%s", sad->request); + if (sad->request[0] == '\0') + audit_log_format(ab, " labels_differ"); + else + audit_log_format(ab, " requested=%s", sad->request); } /** diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 4d6f37644baa..787dcf12f15c 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 3198cfe1dcc6..177d87875394 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 */ }; /* @@ -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 */ {""} }; -- cgit v1.2.3-59-g8ed1b