Add discoreving of device identity
authorKrzysztof Opasiak <k.opasiak@samsung.com>
Fri, 26 Jun 2015 07:49:48 +0000 (09:49 +0200)
committerStanislaw Wadas <s.wadas@samsung.com>
Wed, 2 Dec 2015 12:45:16 +0000 (13:45 +0100)
because we need to distinguish USB device we use device descriptor
(idVendor, idProduct etc.) to create device ID. When checking if
we should grant access we check if selected device node
belengs to this device.

Change-Id: Ifad14d3e62c6aba6c91bd132a112e5ad4e768c3b
Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
USD/src/CMakeLists.txt
USD/src/common/usb-access-map.cpp [new file with mode: 0644]
USD/src/common/usb-access-map.h [new file with mode: 0644]
USD/src/include/usb-security-daemon.h

index 7857ccb0954c19976515d450ac41125866362dce..98871b3dea311b430867f1f43c4a8f6748881e3d 100644 (file)
@@ -110,6 +110,7 @@ SET(COMMON_SOURCES
     ${COMMON_PATH}/common/protocols.cpp
     ${COMMON_PATH}/common/message-buffer.cpp
     ${COMMON_PATH}/common/smack-check.cpp
+    ${COMMON_PATH}/common/usb-access-map.cpp
     ${COMMON_PATH}/dpl/log/src/abstract_log_provider.cpp
     ${COMMON_PATH}/dpl/log/src/dlog_log_provider.cpp
     ${COMMON_PATH}/dpl/log/src/sd_journal_provider.cpp
diff --git a/USD/src/common/usb-access-map.cpp b/USD/src/common/usb-access-map.cpp
new file mode 100644 (file)
index 0000000..75597ab
--- /dev/null
@@ -0,0 +1,310 @@
+/*-*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-*/
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Karol Lewandowski <k.lewandowsk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/**
+ * @file        usb-access-map.cpp
+ * @author      Jan Cybulski <j.cybulski@samsung.com>
+ * @author      Krzysztof Opasiak <k.opasiak@samsung.com>
+ * @version     1.0
+ * @brief       Implementation of classes that gathers information about
+ * applications' access rights to usb files for purpose of raw USB usage.
+ */
+
+#include <usb-access-map.h>
+#include <usb-security-daemon.h>
+#include <dpl/log/log.h>
+#include <cstring>
+#include <limits.h>
+#include <string>
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+
+#include <sys/smack.h>
+#include <linux/usb/ch9.h>
+#include <endian.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define USB_DEVICE_MAJOR 189
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*a))
+
+using namespace std;
+
+namespace USD {
+
+void USBDevicePath::initFromSysFS(const std::string &path)
+{
+    char buf[PATH_MAX];
+    char *ret_chp;
+
+    ret_chp = realpath(path.c_str(), buf);
+    if (!ret_chp)
+        throw USD_API_ERROR_FILE_NOT_EXIST;
+    m_sysPath = string(buf);
+
+    if (m_dev == 0) {
+        /* it is not dev node! */
+        ifstream dev_file(m_sysPath + "/dev");
+        string content;
+        int min, maj;
+        int ret;
+
+        dev_file >> content;
+        ret = sscanf(content.c_str(), "%d:%d", &maj, &min);
+        if (ret < 3)
+            throw USD_API_ERROR_FILE_READ_FAILED;
+
+        if (maj != USB_DEVICE_MAJOR)
+            throw USD_API_ERROR_ACCESS_DENIED;
+
+        m_dev = makedev(maj, min);
+    }
+}
+
+void USBDevicePath::initFromTopology(const std::string &path)
+{
+    string usb_path = path;
+    size_t ret;
+
+    ret = path.find_first_of('/');
+    if (ret != string::npos)
+        usb_path = path.substr(0, ret);
+
+    /*
+     * TODO: This is a good vector of attack.
+     * Revisit this function and check if it is really
+     * safe and any malformed path can lead us outside sysfs
+     * For example: path=../../../../tmp/my_fake_dir"
+     * would work without above code
+     */
+    initFromSysFS(string("/sys/bus/usb/devices/") + path);
+}
+
+void USBDevicePath::initFromDev(const std::string &path)
+{
+    struct stat dev_st;
+    char buf[PATH_MAX];
+    string spath;
+    int ret;
+
+    ret = stat(path.c_str(), &dev_st);
+    if (ret < 0)
+        throw USD_API_ERROR_FILE_READ_FAILED;
+
+    if (!S_ISCHR(dev_st.st_mode) ||
+        major(dev_st.st_dev) != USB_DEVICE_MAJOR)
+        throw USD_API_ERROR_ACCESS_DENIED;
+
+    m_dev = dev_st.st_dev;
+    ret = snprintf(buf, sizeof(buf),
+                   "/sys/dev/chr/%d:%d", major(m_dev), minor(m_dev));
+    /*
+     * If this happened we have really big troubles,
+     * probably it end of the world
+     */
+    if ((unsigned)ret >= sizeof(buf))
+        throw USD_API_ERROR_BUFFER_TOO_SMALL;
+
+    initFromSysFS(buf);
+}
+
+USBDevicePath::USBDevicePath(const string &path,
+                             PathType path_type)
+    : m_dev(0)
+{
+    switch (path_type) {
+    case PATH_TYPE_DEV:
+        initFromDev(path);
+        break;
+    case PATH_TYPE_TOPO:
+        initFromTopology(path);
+        break;
+    case PATH_TYPE_SYSFS:
+        initFromSysFS(path);
+        break;
+    }
+}
+
+const std::string &USBDevicePath::getSysFSPath() const
+{
+    return m_sysPath;
+}
+
+dev_t USBDevicePath::getDev() const
+{
+    return m_dev;
+}
+
+std::ostream &operator<<(std::ostream &stream,
+                                    const USBDevicePath &path)
+{
+
+    stream << '(' << major(path.m_dev) << ':' << minor(path.m_dev) << ", "
+           << path.m_sysPath << ')';
+
+    return stream;
+}
+
+/****** USBDeviceId ******/
+
+USBDeviceId::USBDeviceId(const string &path, USBDevicePath::PathType path_type)
+    : m_path(path, path_type)
+{
+    initDevId(m_path.getSysFSPath());
+}
+
+USBDeviceId::USBDeviceId(const USBDevicePath &path)
+    : m_path(path)
+{
+    initDevId(m_path.getSysFSPath());
+}
+
+void USBDeviceId::initDevId(const std::string &sys_path)
+{
+    int fd;
+    int ret;
+    struct usb_device_descriptor desc;
+    std::string path;
+
+    path += sys_path + "/descriptors";
+
+    fd = open(path.c_str(), O_RDONLY);
+    if (fd < 0)
+        throw USD_API_ERROR_FILE_OPEN_FAILED;
+
+    ret = read(fd, &desc, sizeof(desc));
+    close(fd);
+    if ((unsigned)ret < sizeof(desc))
+        throw USD_API_ERROR_FILE_READ_FAILED;
+
+    m_bcdUSB = le16toh(desc.bcdUSB);
+    m_bDeviceClass = desc.bDeviceClass;
+    m_bDeviceSubClass = desc.bDeviceSubClass;
+    m_bDeviceProtocol = desc.bDeviceProtocol;
+    m_idVendor = le16toh(desc.idVendor);
+    m_idProduct = le16toh(desc.idProduct);
+    m_bcdDevice = le16toh(desc.bcdDevice);
+}
+
+bool USBDeviceId::operator<(const USBDeviceId &r) const
+{
+    int i;
+
+    /*
+     * We don't test major because we know that
+     * all USB devices have the same major
+     */
+#define VALUES(field)                           \
+    { .our = this->field, .other = r.field, }
+
+    struct {
+        int our;
+        int other;
+    } values[] = {
+        {
+            .our = minor(m_path.getDev()),
+            .other = minor(r.m_path.getDev()),
+        },
+        VALUES(m_idVendor),
+        VALUES(m_idProduct),
+        VALUES(m_bcdDevice),
+        VALUES(m_bDeviceClass),
+        VALUES(m_bDeviceSubClass),
+        VALUES(m_bDeviceProtocol),
+        VALUES(m_bcdUSB),
+    };
+
+#undef VALUES
+
+    for (i = 0; (unsigned)i < ARRAY_SIZE(values); ++i)
+        if (values[i].our != values[i].other)
+            return values[i].our < values[i].other;
+
+    return m_path.getSysFSPath() < r.m_path.getSysFSPath();
+}
+
+bool USBDeviceId::operator==(const USBDeviceId &r) const
+{
+#define FIELD_NE(field) (this->field != r.field)
+
+    if (FIELD_NE(m_path.getDev()))
+        return false;
+
+    if (FIELD_NE(m_idVendor))
+        return false;
+
+    if (FIELD_NE(m_idProduct))
+        return false;
+
+    if (FIELD_NE(m_bcdDevice))
+        return false;
+
+    if (FIELD_NE(m_bDeviceClass))
+        return false;
+
+    if (FIELD_NE(m_bDeviceSubClass))
+        return false;
+
+    if (FIELD_NE(m_bDeviceProtocol))
+        return false;
+
+    if (FIELD_NE(m_bcdUSB))
+        return false;
+#undef FIELD_NE
+
+    return m_path.getSysFSPath() == r.m_path.getSysFSPath();
+}
+
+bool USBDeviceId::operator!=(const USBDeviceId &r) const
+{
+    return !(*this == r);
+}
+
+std::ostream &operator<<(std::ostream &stream,
+                                    const USBDeviceId &id)
+{
+#define NAMED_VAL(field) { .name = #field, .val = id.m_##field, }
+    struct {
+        const char *name;
+        int val;
+    } fields[] = {
+        NAMED_VAL(idVendor),
+        NAMED_VAL(idProduct),
+        NAMED_VAL(bcdDevice),
+        NAMED_VAL(bDeviceClass),
+        NAMED_VAL(bDeviceSubClass),
+        NAMED_VAL(bDeviceProtocol),
+        NAMED_VAL(bcdUSB),
+    };
+#undef NAMED_VAL
+    int i = 0;
+
+    stream << "(";
+    for (i = 0; (unsigned)i < ARRAY_SIZE(fields); ++i)
+        stream << fields[i].name << ": " << std::hex << fields[i].val << ", ";
+
+    stream << "devicePath: " << id.m_path;
+
+    stream << ")";
+
+    return stream;
+}
+} /* namespace USD */
diff --git a/USD/src/common/usb-access-map.h b/USD/src/common/usb-access-map.h
new file mode 100644 (file)
index 0000000..d6bb36f
--- /dev/null
@@ -0,0 +1,102 @@
+/*-*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-*/
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Karol Lewandowski <k.lewandowsk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/**
+ * @file        usb-access.h
+ * @author      Jan Cybulski <j.cybulski@samsung.com>
+ * @author      Krzysztof Opasiak <k.opasiak@samsung.com>
+ * @version     1.0
+ * @brief       Header for classes that gathers information about
+ * applications' access rights to usb files for purpose of raw USB usage.
+ */
+
+#ifndef USB_ACCESS_MAP_H_
+#define USB_ACCESS_MAP_H_
+
+#include <string>
+#include <iostream>
+#include <dpl/serialization.h>
+
+namespace USD {
+
+class USBDevicePath
+{
+public:
+    enum PathType {
+        PATH_TYPE_DEV,
+        PATH_TYPE_TOPO,
+        PATH_TYPE_SYSFS,
+    };
+
+    /* Never call this constructor with SysFS path received from user! */
+    USBDevicePath(const std::string &path, PathType path_type);
+    const std::string &getSysFSPath() const;
+    dev_t getDev() const;
+
+    friend std::ostream &operator<<(std::ostream &stream,
+                                    const USBDevicePath &path);
+private:
+    void initFromSysFS(const std::string &path);
+    void initFromTopology(const std::string &path);
+    void initFromDev(const std::string &path);
+    std::string m_sysPath;
+    dev_t m_dev;
+};
+
+/*
+ * As for now identifier may be just values from device descriptor,
+ * but later this may be changed, so more flexible rules may be
+ * introduced.
+ */
+class USBDeviceId
+{
+public:
+    USBDeviceId(const USBDevicePath &path);
+    USBDeviceId(const std::string &path, USBDevicePath::PathType path_type);
+
+    bool operator<(const USBDeviceId &r) const;
+    bool operator==(const USBDeviceId &r) const;
+    bool operator!=(const USBDeviceId &r) const;
+
+    friend std::ostream &operator<<(std::ostream &stream,
+                                    const USBDeviceId &id);
+
+private:
+    void initDevId(const std::string &sys_path);
+
+    uint16_t m_bcdUSB;
+    uint8_t m_bDeviceClass;
+    uint8_t m_bDeviceSubClass;
+    uint8_t m_bDeviceProtocol;
+    uint16_t m_idVendor;
+    uint16_t m_idProduct;
+    uint16_t m_bcdDevice;
+    /*
+     * We should consider here also strings but it requires device
+     * communication, so should be discussed later.
+     * std::string m_iManufacturer;
+     * std::string m_iProduct;
+     * std::string m_iSerialNumber;
+     */
+
+    USBDevicePath m_path;
+};
+
+} /* namespace USD */
+
+#endif /* USB_ACCESS_MAP_H_ */
index 876fc794f7fe270aacfad16c02fef220d9b005f0..103d7b24df1e9334d711ce1724523d8f04359a95 100644 (file)
 /*! \brief   indicating file deletion error  */
 #define USD_API_ERROR_FILE_DELETION_FAILED -28
 
+/*! \brief   indicating file read error  */
+#define USD_API_ERROR_FILE_READ_FAILED -28
+
 /*! \brief   indicating the error with unknown reason */
 #define USD_API_ERROR_UNKNOWN -255
 /** @}*/