Example #1
0
dbus_bool_t
_dbus_marshal_validate_test (void)
{
  DBusString str;
  int i;

  const char *valid_paths[] = {
    "/",
    "/foo/bar",
    "/foo",
    "/foo/bar/baz"
  };
  const char *invalid_paths[] = {
    "bar",
    "bar/baz",
    "/foo/bar/",
    "/foo/",
    "foo/",
    "boo//blah",
    "//",
    "///",
    "foo///blah/",
    "Hello World",
    "",
    "   ",
    "foo bar"
  };

  const char *valid_interfaces[] = {
    "org.freedesktop.Foo",
    "Bar.Baz",
    "Blah.Blah.Blah.Blah.Blah",
    "a.b",
    "a.b.c.d.e.f.g",
    "a0.b1.c2.d3.e4.f5.g6",
    "abc123.foo27"
  };
  const char *invalid_interfaces[] = {
    ".",
    "",
    "..",
    ".Foo.Bar",
    "..Foo.Bar",
    "Foo.Bar.",
    "Foo.Bar..",
    "Foo",
    "9foo.bar.baz",
    "foo.bar..baz",
    "foo.bar...baz",
    "foo.bar.b..blah",
    ":",
    ":0-1",
    "10",
    ":11.34324",
    "0.0.0",
    "0..0",
    "foo.Bar.%",
    "foo.Bar!!",
    "!Foo.bar.bz",
    "foo.$.blah",
    "",
    "   ",
    "foo bar"
  };

  const char *valid_unique_names[] = {
    ":0",
    ":a",
    ":",
    ":.a",
    ":.1",
    ":0.1",
    ":000.2222",
    ":.blah",
    ":abce.freedesktop.blah"
  };
  const char *invalid_unique_names[] = {
    //":-",
    ":!",
    //":0-10",
    ":blah.",
    ":blah.",
    ":blah..org",
    ":blah.org..",
    ":..blah.org",
    "",
    "   ",
    "foo bar"
  };

  const char *valid_members[] = {
    "Hello",
    "Bar",
    "foobar",
    "_foobar",
    "foo89"
  };

  const char *invalid_members[] = {
    "9Hello",
    "10",
    "1",
    "foo-bar",
    "blah.org",
    ".blah",
    "blah.",
    "Hello.",
    "!foo",
    "",
    "   ",
    "foo bar"
  };

  const char *valid_signatures[] = {
    "",
    "sss",
    "i",
    "b"
  };

  const char *invalid_signatures[] = {
    " ",
    "not a valid signature",
    "123",
    ".",
    "(",
    "a{(ii)i}" /* https://bugs.freedesktop.org/show_bug.cgi?id=17803 */
  };

  /* Signature with reason */

  run_validity_tests (signature_tests, _DBUS_N_ELEMENTS (signature_tests),
                      _dbus_validate_signature_with_reason);

  /* Path validation */
  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (valid_paths))
    {
      _dbus_string_init_const (&str, valid_paths[i]);

      if (!_dbus_validate_path (&str, 0,
                                _dbus_string_get_length (&str)))
        {
          _dbus_warn ("Path \"%s\" should have been valid", valid_paths[i]);
          _dbus_assert_not_reached ("invalid path");
        }

      ++i;
    }

  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (invalid_paths))
    {
      _dbus_string_init_const (&str, invalid_paths[i]);

      if (_dbus_validate_path (&str, 0,
                               _dbus_string_get_length (&str)))
        {
          _dbus_warn ("Path \"%s\" should have been invalid", invalid_paths[i]);
          _dbus_assert_not_reached ("valid path");
        }

      ++i;
    }

  /* Interface validation */
  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
    {
      _dbus_string_init_const (&str, valid_interfaces[i]);

      if (!_dbus_validate_interface (&str, 0,
                                     _dbus_string_get_length (&str)))
        {
          _dbus_warn ("Interface \"%s\" should have been valid", valid_interfaces[i]);
          _dbus_assert_not_reached ("invalid interface");
        }

      ++i;
    }

  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
    {
      _dbus_string_init_const (&str, invalid_interfaces[i]);

      if (_dbus_validate_interface (&str, 0,
                                    _dbus_string_get_length (&str)))
        {
          _dbus_warn ("Interface \"%s\" should have been invalid", invalid_interfaces[i]);
          _dbus_assert_not_reached ("valid interface");
        }

      ++i;
    }

  /* Bus name validation (check that valid interfaces are valid bus names,
   * and invalid interfaces are invalid services except if they start with ':')
   */
  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
    {
      _dbus_string_init_const (&str, valid_interfaces[i]);

      if (!_dbus_validate_bus_name (&str, 0,
                                   _dbus_string_get_length (&str)))
        {
          _dbus_warn ("Bus name \"%s\" should have been valid", valid_interfaces[i]);
          _dbus_assert_not_reached ("invalid bus name");
        }

      ++i;
    }

  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
    {
      if (invalid_interfaces[i][0] != ':')
        {
          _dbus_string_init_const (&str, invalid_interfaces[i]);

          if (_dbus_validate_bus_name (&str, 0,
                                       _dbus_string_get_length (&str)))
            {
              _dbus_warn ("Bus name \"%s\" should have been invalid", invalid_interfaces[i]);
              _dbus_assert_not_reached ("valid bus name");
            }
        }

      ++i;
    }

  /* unique name validation */
  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (valid_unique_names))
    {
      _dbus_string_init_const (&str, valid_unique_names[i]);

      if (!_dbus_validate_bus_name (&str, 0,
                                    _dbus_string_get_length (&str)))
        {
          _dbus_warn ("Bus name \"%s\" should have been valid", valid_unique_names[i]);
          _dbus_assert_not_reached ("invalid unique name");
        }

      ++i;
    }

  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (invalid_unique_names))
    {
      _dbus_string_init_const (&str, invalid_unique_names[i]);

      if (_dbus_validate_bus_name (&str, 0,
                                   _dbus_string_get_length (&str)))
        {
          _dbus_warn ("Bus name \"%s\" should have been invalid", invalid_unique_names[i]);
          _dbus_assert_not_reached ("valid unique name");
        }

      ++i;
    }


  /* Error name validation (currently identical to interfaces)
   */
  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
    {
      _dbus_string_init_const (&str, valid_interfaces[i]);

      if (!_dbus_validate_error_name (&str, 0,
                                      _dbus_string_get_length (&str)))
        {
          _dbus_warn ("Error name \"%s\" should have been valid", valid_interfaces[i]);
          _dbus_assert_not_reached ("invalid error name");
        }

      ++i;
    }

  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
    {
      if (invalid_interfaces[i][0] != ':')
        {
          _dbus_string_init_const (&str, invalid_interfaces[i]);

          if (_dbus_validate_error_name (&str, 0,
                                         _dbus_string_get_length (&str)))
            {
              _dbus_warn ("Error name \"%s\" should have been invalid", invalid_interfaces[i]);
              _dbus_assert_not_reached ("valid error name");
            }
        }

      ++i;
    }

  /* Member validation */
  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (valid_members))
    {
      _dbus_string_init_const (&str, valid_members[i]);

      if (!_dbus_validate_member (&str, 0,
                                  _dbus_string_get_length (&str)))
        {
          _dbus_warn ("Member \"%s\" should have been valid", valid_members[i]);
          _dbus_assert_not_reached ("invalid member");
        }

      ++i;
    }

  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (invalid_members))
    {
      _dbus_string_init_const (&str, invalid_members[i]);

      if (_dbus_validate_member (&str, 0,
                                 _dbus_string_get_length (&str)))
        {
          _dbus_warn ("Member \"%s\" should have been invalid", invalid_members[i]);
          _dbus_assert_not_reached ("valid member");
        }

      ++i;
    }

  /* Signature validation */
  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (valid_signatures))
    {
      _dbus_string_init_const (&str, valid_signatures[i]);

      if (!_dbus_validate_signature (&str, 0,
                                     _dbus_string_get_length (&str)))
        {
          _dbus_warn ("Signature \"%s\" should have been valid", valid_signatures[i]);
          _dbus_assert_not_reached ("invalid signature");
        }

      ++i;
    }

  i = 0;
  while (i < (int) _DBUS_N_ELEMENTS (invalid_signatures))
    {
      _dbus_string_init_const (&str, invalid_signatures[i]);

      if (_dbus_validate_signature (&str, 0,
                                    _dbus_string_get_length (&str)))
        {
          _dbus_warn ("Signature \"%s\" should have been invalid", invalid_signatures[i]);
          _dbus_assert_not_reached ("valid signature");
        }

      ++i;
    }

  /* Validate claimed length longer than real length */
  _dbus_string_init_const (&str, "abc.efg");
  if (_dbus_validate_bus_name (&str, 0, 8))
    _dbus_assert_not_reached ("validated too-long string");
  if (_dbus_validate_interface (&str, 0, 8))
    _dbus_assert_not_reached ("validated too-long string");
  if (_dbus_validate_error_name (&str, 0, 8))
    _dbus_assert_not_reached ("validated too-long string");

  _dbus_string_init_const (&str, "abc");
  if (_dbus_validate_member (&str, 0, 4))
    _dbus_assert_not_reached ("validated too-long string");

  _dbus_string_init_const (&str, "sss");
  if (_dbus_validate_signature (&str, 0, 4))
    _dbus_assert_not_reached ("validated too-long signature");

  /* Validate string exceeding max name length */
  if (!_dbus_string_init (&str))
    _dbus_assert_not_reached ("no memory");

  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
    if (!_dbus_string_append (&str, "abc.def"))
      _dbus_assert_not_reached ("no memory");

  if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str)))
    _dbus_assert_not_reached ("validated overmax string");
  if (_dbus_validate_interface (&str, 0, _dbus_string_get_length (&str)))
    _dbus_assert_not_reached ("validated overmax string");
  if (_dbus_validate_error_name (&str, 0, _dbus_string_get_length (&str)))
    _dbus_assert_not_reached ("validated overmax string");

  /* overlong member */
  _dbus_string_set_length (&str, 0);
  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
    if (!_dbus_string_append (&str, "abc"))
      _dbus_assert_not_reached ("no memory");

  if (_dbus_validate_member (&str, 0, _dbus_string_get_length (&str)))
    _dbus_assert_not_reached ("validated overmax string");

  /* overlong unique name */
  _dbus_string_set_length (&str, 0);
  _dbus_string_append (&str, ":");
  while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
    if (!_dbus_string_append (&str, "abc"))
      _dbus_assert_not_reached ("no memory");

  if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str)))
    _dbus_assert_not_reached ("validated overmax string");

  _dbus_string_free (&str);

  /* Body validation; test basic validation of valid bodies for both endian */
  
  {
    int sequence;
    DBusString signature;
    DBusString body;

    if (!_dbus_string_init (&signature) || !_dbus_string_init (&body))
      _dbus_assert_not_reached ("oom");

    sequence = 0;
    while (dbus_internal_do_not_use_generate_bodies (sequence,
                                                     DBUS_LITTLE_ENDIAN,
                                                     &signature, &body))
      {
        DBusValidity validity;

        validity = _dbus_validate_body_with_reason (&signature, 0,
                                                    DBUS_LITTLE_ENDIAN,
                                                    NULL, &body, 0,
                                                    _dbus_string_get_length (&body));
        if (validity != DBUS_VALID)
          {
            _dbus_warn ("invalid code %d expected valid on sequence %d little endian",
                        validity, sequence);
            _dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature));
            _dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body));
            _dbus_assert_not_reached ("test failed");
          }

        _dbus_string_set_length (&signature, 0);
        _dbus_string_set_length (&body, 0);
        ++sequence;
      }
                                                     
    sequence = 0;
    while (dbus_internal_do_not_use_generate_bodies (sequence,
                                                     DBUS_BIG_ENDIAN,
                                                     &signature, &body))
      {
        DBusValidity validity;

        validity = _dbus_validate_body_with_reason (&signature, 0,
                                                    DBUS_BIG_ENDIAN,
                                                    NULL, &body, 0,
                                                    _dbus_string_get_length (&body));
        if (validity != DBUS_VALID)
          {
            _dbus_warn ("invalid code %d expected valid on sequence %d big endian",
                        validity, sequence);
            _dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature));
            _dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body));
            _dbus_assert_not_reached ("test failed");
          }

        _dbus_string_set_length (&signature, 0);
        _dbus_string_set_length (&body, 0);
        ++sequence;
      }

    _dbus_string_free (&signature);
    _dbus_string_free (&body);
  }
  
  return TRUE;
}
/**
 * Creates a message header from potentially-untrusted data. The
 * return value is #TRUE if there was enough memory and the data was
 * valid. If it returns #TRUE, the header will be created. If it
 * returns #FALSE and *validity == #DBUS_VALIDITY_UNKNOWN_OOM_ERROR, 
 * then there wasn't enough memory.  If it returns #FALSE 
 * and *validity != #DBUS_VALIDITY_UNKNOWN_OOM_ERROR then the data was 
 * invalid.
 *
 * The byte_order, fields_array_len, and body_len args should be from
 * _dbus_header_have_message_untrusted(). Validation performed in
 * _dbus_header_have_message_untrusted() is assumed to have been
 * already done.
 *
 * @param header the header (must be initialized)
 * @param mode whether to do validation
 * @param validity return location for invalidity reason
 * @param byte_order byte order from header
 * @param fields_array_len claimed length of fields array
 * @param body_len claimed length of body
 * @param header_len claimed length of header
 * @param str a string
 * @param start start of header, 8-aligned
 * @param len length of string to look at
 * @returns #FALSE if no memory or data was invalid, #TRUE otherwise
 */
dbus_bool_t
_dbus_header_load (DBusHeader        *header,
                   DBusValidationMode mode,
                   DBusValidity      *validity,
                   int                byte_order,
                   int                fields_array_len,
                   int                header_len,
                   int                body_len,
                   const DBusString  *str,
                   int                start,
                   int                len)
{
  int leftover;
  DBusValidity v;
  DBusTypeReader reader;
  DBusTypeReader array_reader;
  unsigned char v_byte;
  dbus_uint32_t v_uint32;
  dbus_uint32_t serial;
  int padding_start;
  int padding_len;
  int i;

  _dbus_assert (start == (int) _DBUS_ALIGN_VALUE (start, 8));
  _dbus_assert (header_len <= len);
  _dbus_assert (_dbus_string_get_length (&header->data) == 0);

  if (!_dbus_string_copy_len (str, start, header_len, &header->data, 0))
    {
      _dbus_verbose ("Failed to copy buffer into new header\n");
      *validity = DBUS_VALIDITY_UNKNOWN_OOM_ERROR;
      return FALSE;
    }

  if (mode == DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY)
    {
      leftover = len - header_len - body_len - start;
    }
  else
    {
      v = _dbus_validate_body_with_reason (&_dbus_header_signature_str, 0,
                                           byte_order,
                                           &leftover,
                                           str, start, len);
      
      if (v != DBUS_VALID)
        {
          *validity = v;
          goto invalid;
        }
    }

  _dbus_assert (leftover < len);

  padding_len = header_len - (FIRST_FIELD_OFFSET + fields_array_len);
  padding_start = start + FIRST_FIELD_OFFSET + fields_array_len;
  _dbus_assert (start + header_len == (int) _DBUS_ALIGN_VALUE (padding_start, 8));
  _dbus_assert (start + header_len == padding_start + padding_len);

  if (mode != DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY)
    {
      if (!_dbus_string_validate_nul (str, padding_start, padding_len))
        {
          *validity = DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
          goto invalid;
        }
    }

  header->padding = padding_len;

  if (mode == DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY)
    {
      *validity = DBUS_VALID;
      return TRUE;
    }

  /* We now know the data is well-formed, but we have to check that
   * it's valid.
   */

  _dbus_type_reader_init (&reader,
                          byte_order,
                          &_dbus_header_signature_str, 0,
                          str, start);

  /* BYTE ORDER */
  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE);
  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == BYTE_ORDER_OFFSET);
  _dbus_type_reader_read_basic (&reader, &v_byte);
  _dbus_type_reader_next (&reader);

  _dbus_assert (v_byte == byte_order);
  header->byte_order = byte_order;

  /* MESSAGE TYPE */
  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE);
  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == TYPE_OFFSET);
  _dbus_type_reader_read_basic (&reader, &v_byte);
  _dbus_type_reader_next (&reader);

  /* unknown message types are supposed to be ignored, so only validation here is
   * that it isn't invalid
   */
  if (v_byte == DBUS_MESSAGE_TYPE_INVALID)
    {
      *validity = DBUS_INVALID_BAD_MESSAGE_TYPE;
      goto invalid;
    }

  /* FLAGS */
  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE);
  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == FLAGS_OFFSET);
  _dbus_type_reader_read_basic (&reader, &v_byte);
  _dbus_type_reader_next (&reader);

  /* unknown flags should be ignored */

  /* PROTOCOL VERSION */
  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE);
  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == VERSION_OFFSET);
  _dbus_type_reader_read_basic (&reader, &v_byte);
  _dbus_type_reader_next (&reader);

  if (v_byte != DBUS_MAJOR_PROTOCOL_VERSION)
    {
      *validity = DBUS_INVALID_BAD_PROTOCOL_VERSION;
      goto invalid;
    }

  /* BODY LENGTH */
  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_UINT32);
  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == BODY_LENGTH_OFFSET);
  _dbus_type_reader_read_basic (&reader, &v_uint32);
  _dbus_type_reader_next (&reader);

  _dbus_assert (body_len == (signed) v_uint32);

  /* SERIAL */
  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_UINT32);
  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == SERIAL_OFFSET);
  _dbus_type_reader_read_basic (&reader, &serial);
  _dbus_type_reader_next (&reader);

  if (serial == 0)
    {
      *validity = DBUS_INVALID_BAD_SERIAL;
      goto invalid;
    }

  _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_ARRAY);
  _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == FIELDS_ARRAY_LENGTH_OFFSET);

  _dbus_type_reader_recurse (&reader, &array_reader);
  while (_dbus_type_reader_get_current_type (&array_reader) != DBUS_TYPE_INVALID)
    {
      DBusTypeReader struct_reader;
      DBusTypeReader variant_reader;
      unsigned char field_code;

      _dbus_assert (_dbus_type_reader_get_current_type (&array_reader) == DBUS_TYPE_STRUCT);

      _dbus_type_reader_recurse (&array_reader, &struct_reader);

      _dbus_assert (_dbus_type_reader_get_current_type (&struct_reader) == DBUS_TYPE_BYTE);
      _dbus_type_reader_read_basic (&struct_reader, &field_code);
      _dbus_type_reader_next (&struct_reader);

      if (field_code == DBUS_HEADER_FIELD_INVALID)
        {
          _dbus_verbose ("invalid header field code\n");
          *validity = DBUS_INVALID_HEADER_FIELD_CODE;
          goto invalid;
        }

      if (field_code > DBUS_HEADER_FIELD_LAST)
        {
          _dbus_verbose ("unknown header field code %d, skipping\n",
                         field_code);
          goto next_field;
        }

      _dbus_assert (_dbus_type_reader_get_current_type (&struct_reader) == DBUS_TYPE_VARIANT);
      _dbus_type_reader_recurse (&struct_reader, &variant_reader);

      v = load_and_validate_field (header, field_code, &variant_reader);
      if (v != DBUS_VALID)
        {
          _dbus_verbose ("Field %d was invalid\n", field_code);
          *validity = v;
          goto invalid;
        }

    next_field:
      _dbus_type_reader_next (&array_reader);
    }

  /* Anything we didn't fill in is now known not to exist */
  i = 0;
  while (i <= DBUS_HEADER_FIELD_LAST)
    {
      if (header->fields[i].value_pos == _DBUS_HEADER_FIELD_VALUE_UNKNOWN)
        header->fields[i].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT;
      ++i;
    }

  v = check_mandatory_fields (header);
  if (v != DBUS_VALID)
    {
      _dbus_verbose ("Mandatory fields were missing, code %d\n", v);
      *validity = v;
      goto invalid;
    }

  *validity = DBUS_VALID;
  return TRUE;

 invalid:
  _dbus_string_set_length (&header->data, 0);
  return FALSE;
}