On 22 Mar 2011, at 19:36, Jonathan Corbet wrote:

> - Does anything bound the size of a message fed into the kernel with
>  write()?  I couldn't find it.  It seems like an application could
>  consume arbitrary amounts of kernel memory.

This patch provides mechanisms for setting an absolute maximum message
size at compile time, and a per-device maximum at runtime.

The patch is relative to the results of the previous set of patches - I
assume this is better than resubmitting all of them for what is a
relatively small change.

> - It would be good to use the kernel's dynamic debugging and tracing
>  facilities rather than rolling your own.
>
> - There's lots of kmalloc()/memset() pairs that could be kzalloc().

I shall address these next, although I'm afraid it may be a few days.
Thanks, by the way, for the timely LWN article on the dynamic debugging
interface.

Signed-off-by: Tony Ibbs <t...@tonyibbs.co.uk>
---
 Documentation/Kbus.txt     |   15 ++++++++++-
 include/linux/kbus_defns.h |   14 ++++++++++-
 ipc/Kconfig                |   32 ++++++++++++++++++++++++-
 ipc/kbus_internal.h        |   11 ++++++++
 ipc/kbus_main.c            |   57 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 126 insertions(+), 3 deletions(-)

diff --git a/Documentation/Kbus.txt b/Documentation/Kbus.txt
index 7cf723fd6..16828b9 100644
--- a/Documentation/Kbus.txt
+++ b/Documentation/Kbus.txt
@@ -1058,6 +1058,18 @@ header file (``kbus_defns.h``). They are:
                 Both Python and C bindings provide a useful function to
                 extract the ``is_bind``, ``binder`` and ``name`` values from
                 the data.
+:MAXMSGSIZE:    Set the maximum size of a KBUS message for this KBUS device,
+                and return the value that is set. This is the size of the
+                largest message that may be written to a KBUS Ksock. Trying
+                to write a longer message will result in an -EMSGSIZE error.
+                An attempt to set this value of 0 will just return the current
+                maximum size. Otherwise, the size requested may not be less
+                than 100, or more than the kernel configuration value
+                KBUS_ABS_MAX_MESSAGE_SIZE.  The default maximum size is set by
+                the kernel configuration value KBUS_DEF_MAX_MESSAGE_SIZE, and
+                is typically 1024.  The size being tested is that returned by
+                the KBUS_ENTIRE_MESSAGE_LEN macro - i.e., the size of an
+                equivalent "entire" message.
 
 /proc/kbus/bindings
 -------------------
@@ -1158,7 +1170,8 @@ as values inside the IOError exception.
 :EINVAL:        Something went wrong (generic error).
 :EMSGSIZE:      On attempting to write a message: Data was written after
                 the end of the message (i.e., after the final end guard
-                of the message).
+                of the message), or an attempt was made to write a message
+                that is too long (see the MAXMSGSIZE ioctl).
 :ENAMETOOLONG:  On attempting to bind, unbind or send a message: The message
                 name is too long.
 :ENOENT:        On attempting to open a Ksock: There is no such device
diff --git a/include/linux/kbus_defns.h b/include/linux/kbus_defns.h
index 82779a6..29f6f99 100644
--- a/include/linux/kbus_defns.h
+++ b/include/linux/kbus_defns.h
@@ -655,9 +655,21 @@ struct kbus_replier_bind_event_data {
  * of the specified values)
  */
 #define KBUS_IOC_REPORTREPLIERBINDS  _IOWR(KBUS_IOC_MAGIC, 17, char *)
+/*
+ * MAXMSGSIZE - set the maximum size of a KBUS message for this KBUS device.
+ * This may not be set to less than 100, or more than
+ * CONFIG_KBUS_ABS_MAX_MESSAGE_SIZE.
+ * arg (in): __u32, the requested maximum message size, or 0 to just
+ *           request what the current limit is, 1 to request the absolute
+ *           maximum size.
+ * arg (out): __u32, the maximum essage size after this call has
+ *            succeeded
+ * retval: 0 for success, negative for failure
+ */
+#define KBUS_IOC_MAXMSGSIZE _IOWR(KBUS_IOC_MAGIC, 18, char *)
 
 /* If adding another IOCTL, remember to increment the next number! */
-#define KBUS_IOC_MAXNR 17
+#define KBUS_IOC_MAXNR 18
 
 #if !__KERNEL__ && defined(__cplusplus)
 }
diff --git a/ipc/Kconfig b/ipc/Kconfig
index 808d742..603b2f6 100644
--- a/ipc/Kconfig
+++ b/ipc/Kconfig
@@ -113,5 +113,35 @@ config KBUS_MAX_UNSENT_UNBIND_MESSAGES
 
          If unsure, choose the default.
 
-endif # KBUS
+config KBUS_ABS_MAX_MESSAGE_SIZE
+       int "Absolute maximum KBUS mesage size"
+       default 1024
+       range 100 2147483647
+       ---help---
+         This sets the absolute maximum size of an individual KBUS message,
+         that is, the size of the largest KBUS message that may be written
+         to a KBUS device node.
+
+         It is not possible to set the maximum message size greater than
+         this value using the KBUS_IOC_MAXMSGSIZE ioctl.
 
+         The size is measured as by the KBUS_ENTIRE_MSG_LEN macro, and
+         includes the message header (80 bytes on a 32-bit system).
+
+config KBUS_DEF_MAX_MESSAGE_SIZE
+       int "Default maximum KBUS mesage size"
+       default 1024
+       range 100 KBUS_ABS_MAX_MESSAGE_SIZE
+       ---help---
+         This sets the default maximum size of an individual KBUS message,
+         that is, the size of the largest KBUS message that may be written
+         to a KBUS device node.
+
+         It may be altered at runtime, for a particular KBUS device, with
+         the KBUS_IOC_MAXMSGSIZE ioctl, up to a limit of
+         KBUS_ABS_MAX_MESSAGE_SIZE.
+
+         The size is measured as by the KBUS_ENTIRE_MSG_LEN macro, and
+         includes the message header (80 bytes on a 32-bit system).
+
+endif # KBUS
diff --git a/ipc/kbus_internal.h b/ipc/kbus_internal.h
index a24fcaf..51d512c 100644
--- a/ipc/kbus_internal.h
+++ b/ipc/kbus_internal.h
@@ -86,6 +86,14 @@
 #define CONFIG_KBUS_DEF_NUM_DEVICES    1
 #endif
 
+#ifndef CONFIG_KBUS_ABS_MAX_MESSAGE_SIZE
+#define CONFIG_KBUS_ABS_MAX_MESSAGE_SIZE 1024
+#endif
+
+#ifndef CONFIG_KBUS_DEF_MAX_MESSAGE_SIZE
+#define CONFIG_KBUS_DEF_MAX_MESSAGE_SIZE 1024
+#endif
+
 /*
  * Our initial array sizes could arguably be made configurable
  * for tuning, if we discover this is useful
@@ -685,6 +693,9 @@ struct kbus_dev {
        struct list_head unsent_unbind_msg_list;
        u32 unsent_unbind_msg_count;
        int unsent_unbind_is_tragic;
+
+       /* The maximum message size that may be written to this device */
+       u32 max_message_size;
 };
 
 /*
diff --git a/ipc/kbus_main.c b/ipc/kbus_main.c
index e99bfca..64f863a 100644
--- a/ipc/kbus_main.c
+++ b/ipc/kbus_main.c
@@ -615,6 +615,8 @@ static int kbus_check_message_written(struct kbus_dev *dev,
        struct kbus_message_header *user_msg =
            (struct kbus_message_header *)&this->user_msg;
 
+       int     msg_size;
+
        if (this == NULL) {
                dev_err(dev->dev, "pid %u [%s]"
                       " Tried to check NULL message\n",
@@ -683,6 +685,15 @@ static int kbus_check_message_written(struct kbus_dev *dev,
                       current->pid, current->comm);
                return -EINVAL;
        }
+
+       msg_size = KBUS_ENTIRE_MSG_LEN(user_msg->name_len, user_msg->data_len);
+       if (msg_size > dev->max_message_size) {
+               dev_err(dev->dev, "pid %u [%s]"
+                       "Message size is %d, more than the maximum %d\n",
+                       current->pid, current->comm,
+                       msg_size, dev->max_message_size);
+               return -EMSGSIZE;
+       }
        return 0;
 }
 
@@ -4150,6 +4161,39 @@ static int kbus_set_report_binds(struct 
kbus_private_data *priv,
        return __put_user(old_value, (u32 __user *) arg);
 }
 
+static int kbus_maxmsgsize(struct kbus_private_data *priv,
+                          unsigned long arg)
+{
+       int retval = 0;
+       u32 requested_max;
+
+       retval = __get_user(requested_max, (u32 __user *) arg);
+       if (retval)
+               return retval;
+
+       kbus_maybe_dbg(priv->dev, "%u MAXMSGSIZE requests %u (was %u)\n",
+                      priv->id, requested_max, priv->dev->max_message_size);
+
+       dev_dbg(priv->dev->dev, "    abs max %d, def max %d\n",
+               CONFIG_KBUS_ABS_MAX_MESSAGE_SIZE,
+               CONFIG_KBUS_DEF_MAX_MESSAGE_SIZE);
+
+       /* A value of 0 is a query for the current length */
+       /* A value of 1 is a query for the absolute maximum */
+       if (requested_max == 0)
+               return __put_user(priv->dev->max_message_size,
+                                 (u32 __user *) arg);
+       else if (requested_max == 1)
+               return __put_user(CONFIG_KBUS_ABS_MAX_MESSAGE_SIZE,
+                                 (u32 __user *) arg);
+       else if (requested_max < 100 ||
+                requested_max > CONFIG_KBUS_ABS_MAX_MESSAGE_SIZE)
+               return -EINVAL;
+
+       priv->dev->max_message_size = requested_max;
+       return __put_user(priv->dev->max_message_size, (u32 __user *) arg);
+}
+
 static long kbus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        int err = 0;
@@ -4357,6 +4401,18 @@ static long kbus_ioctl(struct file *filp, unsigned int 
cmd, unsigned long arg)
                retval = kbus_set_report_binds(priv, dev, arg);
                break;
 
+       case KBUS_IOC_MAXMSGSIZE:
+               /*
+                * Set (and/or query) maximum message size
+                *
+                * arg in: 0 or 1 (for query of current maximum or absolute
+                * maximu) or maximum size wanted
+                * arg out: maximum size allowed
+                * return: 0 means OK, otherwise not OK
+                */
+               retval = kbus_maxmsgsize(priv, arg);
+               break;
+
        default:
                /* *Should* be redundant, if we got our range checks right */
                retval = -ENOTTY;
@@ -4545,6 +4601,7 @@ static int kbus_setup_new_device(int which)
        new->index = which;
 
        new->verbose = KBUS_DEFAULT_VERBOSE_SETTING;
+       new->max_message_size = CONFIG_KBUS_DEF_MAX_MESSAGE_SIZE;
 
        new->dev = device_create(kbus_class_p, NULL,
                                 this_devno, NULL, "kbus%d", which);
-- 
1.7.4.1


--
To unsubscribe from this list: send the line "unsubscribe linux-embedded" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to