From: Paweł Szewczyk
Date: Fri, 26 Feb 2016 14:46:53 +0000 (+0100)
Subject: usbhost: Introduce temporary policy
X-Git-Tag: accepted/tizen/ivi/20160905.065612~2
X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5db7c1ed40dfb537ba0d1b6b8632b3f3750b646b;p=platform%2Fcore%2Fsystem%2Fdeviced.git
usbhost: Introduce temporary policy
Temporary access is limited to single device connection. When device is
disconnected, temporary policy entries related to it are removed. These
entries are never saved.
Change-Id: I158126450dd06ca483f4ee2b5788e8caffcb3f86
Signed-off-by: Paweł Szewczyk
---
diff --git a/src/usbhost/usb-host.c b/src/usbhost/usb-host.c
index e4a48b8..7fb110d 100644
--- a/src/usbhost/usb-host.c
+++ b/src/usbhost/usb-host.c
@@ -91,6 +91,49 @@ struct usbhost_device {
static dd_list *usbhost_list;
+enum policy_value {
+ POLICY_ALLOW_ALWAYS,
+ POLICY_ALLOW_NOW,
+ POLICY_DENY_ALWAYS,
+ POLICY_DENY_NOW,
+};
+
+#define UID_KEY "UnixUserID"
+#define SEC_LABEL_KEY "LinuxSecurityLabel"
+#define ENTRY_LINE_SIZE 256
+
+struct user_credentials {
+ uint32_t uid;
+ char *sec_label;
+};
+
+struct policy_entry {
+ struct user_credentials creds;
+ union {
+ struct {
+ uint16_t bcdUSB;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint16_t idVendor;
+ uint16_t idProduct;
+ uint16_t bcdDevice;
+ } device;
+
+ /* for temporary policy */
+ char devpath[PATH_MAX];
+ };
+
+ enum policy_value value;
+};
+
+static inline int is_policy_temporary(struct policy_entry *entry) {
+ return entry->value == POLICY_ALLOW_NOW ||
+ entry->value == POLICY_DENY_NOW;
+}
+
+dd_list *access_list;
+
static void print_usbhost(struct usbhost_device *usbhost)
{
if (!usbhost)
@@ -217,6 +260,7 @@ static int add_usbhost_list(struct udev_device *dev, const char *devpath)
static int remove_usbhost_list(const char *devpath)
{
struct usbhost_device *usbhost;
+ struct policy_entry *entry;
dd_list *n, *next;
/* find the matched item */
@@ -236,6 +280,14 @@ static int remove_usbhost_list(const char *devpath)
/* for debugging */
_I("USB HOST Removed");
_I("devpath : %s", usbhost->devpath);
+ DD_LIST_FOREACH_SAFE(access_list, n, next, entry) {
+ if (is_policy_temporary(entry) &&
+ strcmp(usbhost->devpath, entry->devpath) == 0) {
+ DD_LIST_REMOVE(access_list, entry);
+ free(entry->creds.sec_label);
+ free(entry);
+ }
+ }
DD_LIST_REMOVE(usbhost_list, usbhost);
free(usbhost->manufacturer);
@@ -459,42 +511,16 @@ static struct uevent_handler uh = {
.uevent_func = uevent_usbhost_handler,
};
-enum policy_value {
- POLICY_ALLOW,
- POLICY_DENY,
-};
-
-#define UID_KEY "UnixUserID"
-#define SEC_LABEL_KEY "LinuxSecurityLabel"
-#define ENTRY_LINE_SIZE 256
-
-struct user_credentials {
- uint32_t uid;
- char *sec_label;
-};
-
-struct policy_entry {
- struct user_credentials creds;
- struct {
- uint16_t bcdUSB;
- uint8_t bDeviceClass;
- uint8_t bDeviceSubClass;
- uint8_t bDeviceProtocol;
- uint16_t idVendor;
- uint16_t idProduct;
- uint16_t bcdDevice;
- } device;
- enum policy_value value;
-};
-
-dd_list *access_list;
-
static const char *policy_value_str(enum policy_value value) {
switch (value) {
- case POLICY_ALLOW:
+ case POLICY_ALLOW_ALWAYS:
return "ALLOW";
- case POLICY_DENY:
+ case POLICY_ALLOW_NOW:
+ return "ALLOW_NOW";
+ case POLICY_DENY_ALWAYS:
return "DENY";
+ case POLICY_DENY_NOW:
+ return "DENY_NOW";
default:
return "UNKNOWN";
}
@@ -502,9 +528,13 @@ static const char *policy_value_str(enum policy_value value) {
static int get_policy_value_from_str(const char *str) {
if (strncmp("ALLOW", str, 5) == 0)
- return POLICY_ALLOW;
+ return POLICY_ALLOW_ALWAYS;
+ if (strncmp("ALLOW_NOW", str, 5) == 0)
+ return POLICY_ALLOW_NOW;
if (strncmp("DENY", str, 4) == 0)
- return POLICY_DENY;
+ return POLICY_DENY_ALWAYS;
+ if (strncmp("DENY_NOW", str, 4) == 0)
+ return POLICY_DENY_NOW;
return -1;
}
@@ -555,6 +585,9 @@ static int store_policy(void)
}
DD_LIST_FOREACH(access_list, elem, entry) {
+ if (is_policy_temporary(entry))
+ continue;
+
ret = marshal_policy_entry(line, ENTRY_LINE_SIZE, entry);
if (ret < 0) {
_E("Serialization failed: %m");
@@ -650,9 +683,10 @@ out:
return ret;
}
-static int get_device_desc(const char *filepath, struct usb_device_descriptor *desc)
+static int get_device_desc(const char *filepath, struct usb_device_descriptor *desc, char *devpath)
{
char *path = NULL;
+ char *rdevpath;
struct stat st;
int ret;
int fd = -1;
@@ -678,6 +712,21 @@ static int get_device_desc(const char *filepath, struct usb_device_descriptor *d
goto out;
}
+ rdevpath = realpath(path, devpath);
+ if (!rdevpath) {
+ return -ENOMEM;
+ _E("realpath failed");
+ }
+
+ free(path);
+
+ ret = asprintf(&path, "/sys/dev/char/%d:%d/descriptors", major(st.st_rdev), minor(st.st_rdev));
+ if (ret < 0) {
+ ret = -ENOMEM;
+ _E("asprintf failed");
+ goto out;
+ }
+
_I("Opening descriptor at %s", path);
fd = open(path, O_RDONLY);
if (fd < 0) {
@@ -708,32 +757,44 @@ static void store_idler_cb(void *data)
store_policy();
}
+int get_policy_from_user(struct user_credentials *cred, struct usb_device_descriptor *desc)
+{
+ /* TODO */
+
+ return POLICY_DENY_NOW;
+}
+
static int get_policy_value(const char *path, struct user_credentials *cred)
{
struct usb_device_descriptor desc;
int ret;
dd_list *elem;
struct policy_entry *entry;
+ char devpath[PATH_MAX];
+ int value;
memset(&desc, 0, sizeof(desc));
_I("Requested access from user %d to %s", cred->uid, path);
- ret = get_device_desc(path, &desc);
+ ret = get_device_desc(path, &desc, devpath);
if (ret < 0) {
_E("Could not get device descriptor");
return ret;
}
DD_LIST_FOREACH(access_list, elem, entry) {
- if (entry->creds.uid != cred->uid
- || strncmp(entry->creds.sec_label, cred->sec_label, strlen(cred->sec_label)) != 0
- || entry->device.bcdUSB != le16toh(desc.bcdUSB)
- || entry->device.bDeviceClass != desc.bDeviceClass
- || entry->device.bDeviceSubClass != desc.bDeviceSubClass
- || entry->device.bDeviceProtocol != desc.bDeviceProtocol
- || entry->device.idVendor != le16toh(desc.idVendor)
- || entry->device.idProduct != le16toh(desc.idProduct)
- || entry->device.bcdDevice != le16toh(desc.bcdDevice))
+ if(entry->creds.uid != cred->uid
+ || strncmp(entry->creds.sec_label, cred->sec_label, strlen(cred->sec_label)) != 0)
+ continue;
+
+ if (is_policy_temporary(entry) ? strncmp(entry->devpath, devpath, PATH_MAX) :
+ entry->device.bcdUSB != le16toh(desc.bcdUSB)
+ || entry->device.bDeviceClass != desc.bDeviceClass
+ || entry->device.bDeviceSubClass != desc.bDeviceSubClass
+ || entry->device.bDeviceProtocol != desc.bDeviceProtocol
+ || entry->device.idVendor != le16toh(desc.idVendor)
+ || entry->device.idProduct != le16toh(desc.idProduct)
+ || entry->device.bcdDevice != le16toh(desc.bcdDevice))
continue;
_I("Found matching policy entry: %s", policy_value_str(entry->value));
@@ -741,9 +802,8 @@ static int get_policy_value(const char *path, struct user_credentials *cred)
return entry->value;
}
- /* TODO ask user for policy */
+ value = get_policy_from_user(cred, &desc);
- /* Allow always */
entry = calloc(sizeof(*entry), 1);
if (!entry) {
_E("No memory");
@@ -758,26 +818,42 @@ static int get_policy_value(const char *path, struct user_credentials *cred)
}
strncpy(entry->creds.sec_label, cred->sec_label, strlen(cred->sec_label));
- entry->device.bcdUSB = le16toh(desc.bcdUSB);
- entry->device.bDeviceClass = desc.bDeviceClass;
- entry->device.bDeviceSubClass = desc.bDeviceSubClass;
- entry->device.bDeviceProtocol = desc.bDeviceProtocol;
- entry->device.idVendor = le16toh(desc.idVendor);
- entry->device.idProduct = le16toh(desc.idProduct);
- entry->device.bcdDevice = le16toh(desc.bcdDevice);
- entry->value = POLICY_ALLOW;
-
- _I("Added policy entry: %d %s %04x %02x %02x %02x %04x %04x %04x %s",
- entry->creds.uid,
- entry->creds.sec_label,
- entry->device.bcdUSB,
- entry->device.bDeviceClass,
- entry->device.bDeviceSubClass,
- entry->device.bDeviceProtocol,
- entry->device.idVendor,
- entry->device.idProduct,
- entry->device.bcdDevice,
- policy_value_str(entry->value));
+
+ switch (value) {
+ case POLICY_ALLOW_ALWAYS:
+ case POLICY_DENY_ALWAYS:
+ entry->device.bcdUSB = le16toh(desc.bcdUSB);
+ entry->device.bDeviceClass = desc.bDeviceClass;
+ entry->device.bDeviceSubClass = desc.bDeviceSubClass;
+ entry->device.bDeviceProtocol = desc.bDeviceProtocol;
+ entry->device.idVendor = le16toh(desc.idVendor);
+ entry->device.idProduct = le16toh(desc.idProduct);
+ entry->device.bcdDevice = le16toh(desc.bcdDevice);
+
+ _I("Added policy entry: %d %s %04x %02x %02x %02x %04x %04x %04x %s",
+ entry->creds.uid,
+ entry->creds.sec_label,
+ entry->device.bcdUSB,
+ entry->device.bDeviceClass,
+ entry->device.bDeviceSubClass,
+ entry->device.bDeviceProtocol,
+ entry->device.idVendor,
+ entry->device.idProduct,
+ entry->device.bcdDevice,
+ policy_value_str(value));
+ break;
+ case POLICY_ALLOW_NOW:
+ case POLICY_DENY_NOW:
+ strncpy(entry->devpath, devpath, strlen(devpath));
+ _I("Added temporary policy entry: %d %s %s %s",
+ entry->creds.uid,
+ entry->creds.sec_label,
+ entry->devpath,
+ policy_value_str(value));
+ break;
+ }
+
+ entry->value = value;
DD_LIST_APPEND(access_list, entry);
ret = add_idle_request(store_idler_cb, NULL);
@@ -955,7 +1031,8 @@ static DBusMessage *open_device(E_DBus_Object *obj, DBusMessage *msg)
ret = get_policy_value(path, &cred);
switch (ret) {
- case POLICY_ALLOW:
+ case POLICY_ALLOW_NOW:
+ case POLICY_ALLOW_ALWAYS:
fd = open(path, O_RDWR);
if (fd < 0) {
ret = -errno;
@@ -963,7 +1040,8 @@ static DBusMessage *open_device(E_DBus_Object *obj, DBusMessage *msg)
} else
ret = 0;
break;
- case POLICY_DENY:
+ case POLICY_DENY_NOW:
+ case POLICY_DENY_ALWAYS:
ret = -EACCES;
break;
default: