smackfs: do not trust `count' in inodes write()s
authorAhmed S. Darwish <darwish.07@gmail.com>
Thu, 13 Mar 2008 19:32:34 +0000 (12:32 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Mar 2008 20:11:43 +0000 (13:11 -0700)
Smackfs write() implementation does not put a higher bound on the number of
bytes to copy from user-space.  This may lead to a DOS attack if a malicious
`count' field is given.

Assure that given `count' is exactly the length needed for a /smack/load rule.
 In case of /smack/cipso where the length is relative, assure that `count'
does not exceed the size needed for a buffer representing maximum possible
number of CIPSO 2.2 categories.

Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
Acked-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
security/smack/smack.h
security/smack/smackfs.c

index a21a0e907ab34092017e6a67243a1ad93b3be171..62c1e982849d9b1ab83c38c1bc6bc9df68749e77 100644 (file)
 #define SMK_MAXLEN     23
 #define SMK_LABELLEN   (SMK_MAXLEN+1)
 
-/*
- * How many kinds of access are there?
- * Here's your answer.
- */
-#define SMK_ACCESSDASH '-'
-#define SMK_ACCESSLOW  "rwxa"
-#define SMK_ACCESSKINDS        (sizeof(SMK_ACCESSLOW) - 1)
-
 struct superblock_smack {
        char            *smk_root;
        char            *smk_floor;
index 358c92c1a153df7f943d09fdc3634ffffc47a632..afe7c9b0732ac6c16ae6677bbfe1ca0ca5ecf799 100644 (file)
@@ -81,10 +81,23 @@ static struct semaphore smack_write_sem;
 /*
  * Values for parsing cipso rules
  * SMK_DIGITLEN: Length of a digit field in a rule.
- * SMK_CIPSOMEN: Minimum possible cipso rule length.
+ * SMK_CIPSOMIN: Minimum possible cipso rule length.
+ * SMK_CIPSOMAX: Maximum possible cipso rule length.
  */
 #define SMK_DIGITLEN 4
-#define SMK_CIPSOMIN (SMK_MAXLEN + 2 * SMK_DIGITLEN)
+#define SMK_CIPSOMIN (SMK_LABELLEN + 2 * SMK_DIGITLEN)
+#define SMK_CIPSOMAX (SMK_CIPSOMIN + SMACK_CIPSO_MAXCATNUM * SMK_DIGITLEN)
+
+/*
+ * Values for parsing MAC rules
+ * SMK_ACCESS: Maximum possible combination of access permissions
+ * SMK_ACCESSLEN: Maximum length for a rule access field
+ * SMK_LOADLEN: Smack rule length
+ */
+#define SMK_ACCESS    "rwxa"
+#define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1)
+#define SMK_LOADLEN   (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN)
+
 
 /*
  * Seq_file read operations for /smack/load
@@ -229,14 +242,10 @@ static void smk_set_access(struct smack_rule *srp)
  * The format is exactly:
  *     char subject[SMK_LABELLEN]
  *     char object[SMK_LABELLEN]
- *     char access[SMK_ACCESSKINDS]
- *
- *     Anything following is commentary and ignored.
+ *     char access[SMK_ACCESSLEN]
  *
- * writes must be SMK_LABELLEN+SMK_LABELLEN+4 bytes.
+ * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes.
  */
-#define MINIMUM_LOAD (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSKINDS)
-
 static ssize_t smk_write_load(struct file *file, const char __user *buf,
                              size_t count, loff_t *ppos)
 {
@@ -253,7 +262,7 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
                return -EPERM;
        if (*ppos != 0)
                return -EINVAL;
-       if (count < MINIMUM_LOAD)
+       if (count != SMK_LOADLEN)
                return -EINVAL;
 
        data = kzalloc(count, GFP_KERNEL);
@@ -513,7 +522,7 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
                return -EPERM;
        if (*ppos != 0)
                return -EINVAL;
-       if (count <= SMK_CIPSOMIN)
+       if (count < SMK_CIPSOMIN || count > SMK_CIPSOMAX)
                return -EINVAL;
 
        data = kzalloc(count + 1, GFP_KERNEL);
@@ -547,7 +556,7 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
        if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM)
                goto out;
 
-       if (count <= (SMK_CIPSOMIN + catlen * SMK_DIGITLEN))
+       if (count != (SMK_CIPSOMIN + catlen * SMK_DIGITLEN))
                goto out;
 
        memset(mapcatset, 0, sizeof(mapcatset));