The USB inhibitor

One more post about my work on the USB inhibitor.

The class, implemented in python works like this: I can block all the new connected USB devices or allow only some devices (like video devices, HID devices etc.) to connect.

In the demo I used one mouse and one stick.

The mouse

The stick

On the next videos you can see how usb-inhibitor works: blocking all devices and how we can enable some of them calling the inhibitor with specific parameters.

First one, all the devices are blocked:

Then allow only mass storage devices:

Allow only HID devices:

And in the last video allow HID and mass storage devices:

Also using the inhibitor class and a system D-bus, I’ve created a gnome-shell-extension that blocks all the the USB devices when is turned on. Also the extension runs even when the screen is blocked (then is turned automatically on to block new devices). You have to trust me that I really connect the devices while is turned on/off.

That was for now, see you in the next postūüėÄ

In real open source, you have the right to control your own destiny.” – Linus Torvalds

The Road to GUADEC 2015; a new face

This year I was at GUADEC (GNOME Users And Developers European Conference), that took place in Gothenburg, Sweden.

It was a nice experience, where I met cool people and seen a little of what Sweden has to offer.

  1. The Flight

It wasn’t a direct flight, so we (me and two other friends that also attended GUADEC) had to make a stopover in Amsterdam. Because we knew this we took some tickets in order to have 5 hours to visit Amsterdam.

The back flight, from Amsterdam to Romania, was more “interesting” in the sense that me and one of my friends were very close to lose the flight because we forget were were the baggage lockers. Luckily, one guy from the airport security knew where that lockers were to be found and we caught the plane.:)

Sorry for the dirty window

2. Amsterdam

When we arrived in Amsterdam, we knew we had to reach Central Station, and from there we could visit some of the city. We spent much of our time walking around at first, but when we returned from Sweden, we visited The Amsterdam Dungeon. Here we walked from room to room (dark and small ones) and different actors presented us some of Amsterdams history.

We also wanted to visit the Madame Tussauds but it was a very huge queue and we had to do something else: Amsterdam is full of tourists.

3. Gothenburg

The final destination. I would stay in this city for 6 days.

In the first day I met my mentor, Tobias Mueller aka Tobi, a very cool and energetic person and later he introduced me to a lot of GNOME folks.

I missed some of the talks, but Bastian did a great job and we all have the recorded talks right here. Thanks, Bastian!

At the interns lightning talks (I had a talk also) I had some emotions, but everything came out good.

In the last days, I participated at a BoF about gnome-shell-extensions and some of the ideas discussed can be found here (I only stayed in my corner and listened to the different ideas).

Also, Oliver took us to a field trip, but a group of 4 people (me included) managed to get lost. We tried to catch up with them, but with no success; somewhere we climbed a small hill, I think there we took another route.

In the final day we went to a park, near where we stayed, Liseberg, and there were amazing rides. The coolest one was the AtmosFear.

In the end, I want to thank my mentor for the good time, Florian Mullner for helping me with my extension and the GNOME Foundation for sponsoring my travel.

“Be the change you want to see in the world.” –¬†Mohandas Gandhi

gnome-foundation-sponsored-badge

How the system deals with USB devices

Hello, again.

In this post I will talk about the traffic that an USB device generates (when it’s driver is automatically loaded when the device is connected) and the different output when the device driver is not automatically loaded.

For this it would be used an open-source package, wireshark, that allows a person to monitor the sent/received packets.


First of all, to be able to monitor the USB there must be a module loaded “usbmon“. To load the module one should only run the following command in his terminal: modprobe usbmon and now you can open wireshark and start monitoring the traffic. Also wireshark has some filter capabilities that you may like to use, to not have all the transferred packets in your output.

Let’s first see the output when no USB device is connected:

Screenshot from 2015-07-02 21:55:36

Here it is pretty simple, the host ask for the status of the ports, and then it receives it’s answer:). Some of the info are: if the port is enabled, suspended, powered. Also here the host send a series of requests asking for the device file descriptor and the device answers accordingly.
And this is all that is shown.

Now after a new device is connected (memory storage USB), let’s check a part of wireshark’s output:

Screenshot from 2015-07-02 22:23:01

In the image there is the traffic created by that device (only a chunk of it).
The URB (from the image) stands for USB request block and is like a ‘packet’ with data; used for a communication between the host and an USB endpoint.


Now let’s see what happens when a USB stick is plugged in and the system would not automatically bind the driver when I connect the device. To do this is pretty simple, you only put the “0” value in the /sys/bus/usb/drivers_autoprobe file. Something like this, from the CLI, echo 0 | sudo tee /sys/bus/usb/drivers_autoprobe.

Now let’s see the output from wireshark when the system will not automatically load the drivers for the new connected USB devices.

Part of some output would not be in the image because is the same as where the system would automatically bind the device (when the host requests the status of the ports).

Screenshot from 2015-07-03 01:39:32

It seems like the system would only make the standard requests (excluding the SETs part, there are only the GETs). Here there is no continuous traffic monitored by the wireshark like in the first case, when the driver would load automatically.

Here someone could also observer that there are 2 GET DESCRIPTOR Request/Response CONFIGURATION. Why this? Because in the first Request, the host does not know how many bytes to allocate for all the descriptors. The host first send a message to the device with the field wLength = 9 (bytes), the space needed by the configuration descriptor:

Screenshot from 2015-07-17 18:22:46


bLength -- 1 byte
bDescriptorType -- 1 byte
wTotalLength -- 2 bytes
bNumInterfaces -- 1 byte
bConfigurationValue -- 1 byte
iConfiguration -- 1 byte
bmAttributes -- 1 byte
bMaxPower -- 1 byte

Next the¬†device (Response) would send the total size that the¬†host would have to allocate¬†(wTotalLength –¬†in this space the configuration descriptor is included).

Screenshot from 2015-07-17 18:23:12

Now the¬†host would send another¬†Request where the¬†bLength = wTotalLength and the¬†device would¬†Respond with a message that contains it’s descriptors.

Screenshot from 2015-07-17 18:23:12

And the Response:

Screenshot from 2015-07-17 18:23:20

Also, by disabling the auto-loading of the drivers, there should not be any further traffic with the device.

If the device was connected, while in drivers_autoload file was 0 and then (without disconnecting the device and connecting it again) is written 1 in the file then the device would remain unseen and wireshark would not show any further output. This happens because there is no new interrupt signal that the computer can catch so that it can set an active configuration and further some active interfaces.

All the USB devices comes with a set of configurations and can export multiple interfaces (for each specific configuration) – some endpoints.

Eg: A more fancy keyboard with a display can have one configuration and two interfaces: one for the effective keyboard and one for the screen. Each interface is attached to its specific driver.

For binding the device, one should know what Interface and what Configuration is needed. After having that information is needed to first set the wanted configuration in the /sys/bus/usb/device/bus_id/bConfigurationValue (you can find the bus_id by simply having a look at dmesg command output). After setting the wanted configuration, you must now load the driver for a wanted interface and for doing this you could simply write echo bus_id:Configuration_value (the one you selected).Interface_value | sudo tee /sys/bus/usb/drivers_probe.

Until now, I had talked a lot about how a device connects to the system, but an interesting thing is how the kernel knows which driver to load for a specific device. The system knows what driver to handle a specific interface by looking at the modalias (a file that contains hardware information about the device like the vendor id, product id, device class, device subclass etc.).


Eg: usb:v058Fp6387d010Bdc00dsc00dp00ic08isc06ip50in00

How is formed:

usb:viVendorpiProductdbcdDevicedcbDeviceClassdscbDeviceSubClass
dpbDeviceProtocolicbInterfaceClassiscbInterfaceSubClassipbInterfaceProtocol

The system uses an alias model for getting the module for a device and then bind that device to its specific drivers.

You can take a look at the aliases with: less /lib/modules/`uname -r`/modules.alias.


# Aliases extracted from modules themselves.
alias pci:v00008086d00000958sv*sd*bc*sc*i* iosf_mbi
alias pci:v00008086d00002280sv*sd*bc*sc*i* iosf_mbi
alias pci:v00008086d00000F00sv*sd*bc*sc*i* iosf_mbi
alias crypto-aes-asm aes_x86_64
alias aes-asm aes_x86_64
alias crypto-aes aes_x86_64
alias aes aes_x86_64
alias crypto-des-asm des3_ede_x86_64
alias des-asm des3_ede_x86_64
alias crypto-des des3_ede_x86_64
alias des des3_ede_x86_64
alias crypto-des3_ede-asm des3_ede_x86_64
alias des3_ede-asm des3_ede_x86_64

The asterix (*) means has the same meaning as in globbing Рany character, any number of times. This is used to match multiple device with that specific module.

Also those set of descriptors: device descriptor, configuration descriptor, interface descriptor and endpoint descriptor can identify an USB device and tell the computer the purpose/purposes of that device.

Depending on a specific value of a field one can tell the what is the role of the connected device: bDeviceClass (from the device descriptor). Also, this field may be 0x00, which means that each interface specifies its class (think at a video camera that can server the role of a video camera, duh…and the role of a microphone) – the bInterfaceClass. For a full list of the classes that a device may have you can take a look¬†here.

This is for today, guys. Thanks for reading and I hope you find some interesting information.

“If programmers deserve to be rewarded for creating innovative programs, by the same token they deserve to be punished if they restrict the use of these programs.” Richard Stallman

Hope you are having a great day,
George

D-Bus Tutorial for Python

Those days I had to make a D-Bus server and client in python and I thought to share with you guys some things about the D-Bus.

First of all, what is D-Bus? Well, D-Bus is a system that offers a communication channel for multiple programs.

Someone must also distinguish between: session and system bus.

The session bus is specific for each user, while the system bus is specially designed for the state of the whole system and can change this state (like adding a new storage device, the internet connection suffers some modification).


“Talk is cheap, show me the code”¬† Linus Torvalds

One example of a session bus server is the following:

#! /usr/bin/env python3

# D-Bus Server -- Session Bus

from gi.repository import GLib
import dbus
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop

class Session_DBus(dbus.service.Object):

    def __init__(self):
        bus_name = dbus.service.BusName('org.me.test_session', bus=dbus.SessionBus())
         dbus.service.Object.__init__(self, bus_name, '/org/me/test_session')

    # Interface and Method
    @dbus.service.method('org.me.test1')
    def session_bus_message1(self):
        return "Session Bus 1"

    # Different Interface and different Method
    # The method must not have not the same name as the first
    @dbus.service.method('org.me.test2')
    def session_bus_message2(self):
        return "Session Bus 2"

    # Method with arguments
    @dbus.service.method('org.me.test2')
    def session_bus_strings(self, string1, string2):
        return string1 + " " + string2

DBusGMainLoop(set_as_default=True)
dbus_service = Session_DBus()

try: 
    GLib.MainLoop().run() 
except KeyboardInterrupt: 
    print("\nThe MainLoop will close...") 
    GLib.MainLoop().quit() 

And the client (2 versions):

Vers1

#!/usr/bin/env python3                                              

# D-Bus Client V1 -- Session Bus

import dbus                                                                    

bus = dbus.SessionBus()                                                       
session = bus.get_object("org.me.test_session", "/org/me/test_session")         
                                                                                
method_message1 = session.get_dbus_method('session_bus_message1', 'org.me.test1')
method_message2 = session.get_dbus_method('session_bus_message2', 'org.me.test2')
method_message3 = session.get_dbus_method('session_bus_strings', 'org.me.test2')                                                                                                             

# Call the methods with their specific parameters                               
print(method_message1())                                      
print(method_message2())                                      
print(method_message3("Hello", "world")) 

Vers2

#!/usr/bin/env python3                                                         

# D-Bus Client V2 -- Session Bus         
                                                                  
import dbus                                                                     
                                                                                
bus = dbus.SessionBus()                                                         
session = bus.get_object("org.me.test_session", "/org/me/test_session")         
                                                                                
interface1 = dbus.Interface(session, "org.me.test1")                            
interface2 = dbus.Interface(session, "org.me.test2")                            
                                                                                
# Call the methods using the interface                                          
print(interface1.session_bus_message1())                                        
print(interface2.session_bus_message2())                                        
print(interface2.session_bus_strings("Hello", "world"))   

For the client¬†scripts to run, one must first run the script for the¬†server¬†and after that to run the clients. Also if you want to have to have the¬†server initiated (to not manually run it) you could create a file in /usr/share/dbus-1/service/; let’s say¬†org.me.test_session.config¬†with the following content:

[D-BUS Service]
Name=org.me.test_session
Exec=server_location

After this you can run only the clients and the system would know where server part is and how to handle it. Also, do not forget to make the server script executable:

chmod +x server.py

For the system bus server you would need only to modify line 13 from the¬†sessionbus server and line 7 from the client scripts; to replace¬†SessionBus()¬†with¬†SystemBus(). Let’s also change the names for the methods and for the service.

The final code would look like this:


#!/usr/bin/env python3

# D-Bus Server -- Server Bus

from gi.repository import GLib
import dbus
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop

class Session_DBus(dbus.service.Object):


        def __init__(self):
                bus_name = dbus.service.BusName('org.me.test_server', bus=dbus.SystemBus())
                dbus.service.Object.__init__(self, bus_name, '/org/me/test_server')

        # Interface and Method
        @dbus.service.method('org.me.test1')
        def session_bus_message1(self):
                return "Server Bus 1"


        # Different Interface and different Method
        # The method must not have not the same name as the first 
        @dbus.service.method('org.me.test2')
        def session_bus_message2(self):
                return "Server Bus 2"


        # Method with arguments
        @dbus.service.method('org.me.test2')
        def session_bus_strings(self, string1, string2):
                return string1 + " " + string2


DBusGMainLoop(set_as_default=True)
dbus_service = Session_DBus()

try: 
    GLib.MainLoop().run() 
except KeyboardInterrupt: 
    print("\nThe MainLoop will close...") 
    GLib.MainLoop().quit() 

And for the clients it would look something like this:
Vers1

#! /usr/bin/env python3

import dbus

bus = dbus.SystemBus()
system = bus.get_object("org.me.test_system", "/org/me/test_system")

# Get each method for the specific interface
method_message1 = system.get_dbus_method('system_bus_message1', 'org.me.test1')
method_message2 = system.get_dbus_method('system_bus_message2', 'org.me.test2')
method_message3 = system.get_dbus_method('system_bus_strings', 'org.me.test2')

# Call the methods with their specific parameters
print(method_message1())
print(method_message2())
print(method_message3("Hello", "world"))

Vers2

#!/usr/bin/env python3

import dbus

bus = dbus.SystemBus()
system = bus.get_object("org.me.test_system", "/org/me/test_system")

interface1 = dbus.Interface(system, "org.me.test1")
interface2 = dbus.Interface(system, "org.me.test2")

# Call the methods using the interface
print(interface1.system_bus_message1())
print(interface2.system_bus_message2())
print(interface2.system_bus_strings("Hello", "world")

Of course, if you try the same thing now: run the server and then test the clients you would see that you get an error after trying to turn on the server: a message saying that a specific connection is not allowed to own a service. This thing is because (remember from the first lines of the post) you try (as a regular user) to run a D-Bus that may change the entire system state.

To run the server and test the clients you could to the following:

  1. Create a file in /etc/dbus-1/system.d/ with the name org.me.test_system.conf with the following content:
  2. <!DOCTYPE busconfig PUBLIC                                                      
     "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"                          
     "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">                 
                                                                                     
    <busconfig>                                                                     
        <!-- Owned only by the root -->                                            
        <policy user="root">                                                        
            <allow own="*"/>                                                        
        </policy>                                                                   
                                                                                     
        <!-- What to allow for users -->                                           
        <policy context="default">                                                  
            <allow send_destination="*"/>                                           
            <allow send_interface="*"/>                                             
        </policy>                                                                   
    </busconfig>  
    
  3. Run the server and then you can test the clients:).

Also if you want to only to run the clients (the server to automatically kick in) you can create a file in /usr/share/dbus-1/system-services/ with the name org.me.test_system.service that would contain the following lines:

[D-BUS Service]
Name=org.me.test_system
Exec=server_location
User=root

That is all for now and I hope you found this tutorial helpingūüėÄ.

“In vain have you acquired knowledge¬†if you have not imparted it to others.”
Deuteronomy Rabbah

Have a great day,
George

Ban USB devices from the ports

An USB device has some descriptors and based on them we could find out information about that connected device.

But here comes a problem, what if a device tells us it is what he is not (like a HID device). Well, in that case the driver would be automatically loaded and someone could have access to our computer.

Screenshot from 2015-06-09 20:32:39

Lucky for us, we can manually¬†“unload a driver” using the unbind special file. Unload a driver is not specifically a correct term, you do not really unload it, but you¬†unbind the device from that driver.

By simply writing (could use echo) the bus id of the device to that file, would cause the device to not be usable.

Screenshot from 2015-06-09 20:39:15

To make it usable again, simply write the same bus id of the device to the bind file.

Screenshot from 2015-06-09 20:39:59

By simply doing this, you could play with the device and allow it to be seen or not by your PC.

This could be easily implemented in Python, simply opening the bind/unbind file and writing in it a specific bus id.

Regards,
George

GSoC 2015!

This year I have been accepted to GSoC!

Google Summer of Code is an international program (started in 2005), where accepted students learn about open-source by developing, during the summer, a program. With what do you remain after a coding summer? Well, you will meet a nice community in which you could remain as a developer (for the organization that accepted you, GNOME in my case), you will hone you programming skills and also you will receive 5.500$ for completing the program.

The project I will work on is a security based one and is called Disable USB on lockscreen. Under the guidance of Tobias Mueller, I will try to develop a system that will block the USB port if the screen is locked and if the entered device is not a familiar one (a device that was connected in the past).

This is the core of the project, but I will try to do other little things that it will make the program more flexible.

Until now, I made an application that can detect if a new USB device has been connected and asks the user if he wants to add it to a trusted device list. For every connected device the device descriptors would be collected and every device will get an unique id formed from this descriptors.

usb devices

Each connected USB, that we trust, would be hold into a file named ‘known_devices’ (at least for now) in json format.

File known devices

This is only the start part of the project, only the root, but it would be improved into a more complex application ^_^

This is it for now! I hope you enjoyed reading the first blog post about my experience with GSoC and see you again soon!

Regards,
George