Smack: adds smackfs/ptrace interface
authorLukasz Pawelczyk <l.pawelczyk@partner.samsung.com>
Tue, 11 Mar 2014 16:07:06 +0000 (17:07 +0100)
committerStephane Desneux <stephane.desneux@open.eurogiciel.org>
Wed, 4 Feb 2015 10:23:20 +0000 (11:23 +0100)
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: If5d887a86b8d05ac46c82e1e7e123b86a5d62ddb
Signed-off-by: Lukasz Pawelczyk <l.pawelczyk@partner.samsung.com>
Signed-off-by: Rafal Krypa <r.krypa@samsung.com>
Documentation/security/Smack.txt
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c

index 7a2d30c..5597917 100644 (file)
@@ -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.
index b9dfc4e..fade085 100644 (file)
@@ -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;
index f161deb..c062e94 100644 (file)
@@ -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);
 }
 
 /**
index 23d90cd..d430977 100644 (file)
@@ -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;
 }
index 3198cfe..177d878 100644 (file)
@@ -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 */
                        {""}
        };