Mint 19 + Kodi 18 + Intel NUC i3

I'm finally upgrading my OS and it's time for a follow up on my popular post on setting up Kodi on Ubuntu 14.04.  It was invaluable to me in re-figuring out bits and pieces and some things have changed.

Rather than write out what's changed explicitly, I'll write this as a fresh guide and make notes when something is different than it was 4 years ago.

I'm using Linux Mint 19 now, which is based off Ubuntu 18.04.  These instructions will likely work fine for Ubuntu 18.04.  I'm using Kodi 18 (Leia) on an Intel NUC i3 D34010WYK.  As I write this Kodi 18 is on Release Candidate 3 (I was really hoping they'd have the final build out by now, but now is when I have time off).  Not a problem though, switching the PPA is easy (see below).

Update NUC’s UEFI

I grabbed the latest firmware from Intel (version 50) and flashed it onto the NUC.  Glad to see Intel used a sane process.  Just grab the .BIO file and put it on a USB flash drive.  Upon boot, hit F7 and navigate to the BIOS Flash Update Tool.

Install Linux Mint 19.1

I then installed Mint 19.1.  I won't cover that in this post.  Plenty of better places to find that information.  I'm using the 64-bit distribution.

Install Kodi 18

The Kodi Wiki install guide is pretty clear:

$ sudo apt install software-properties-common
$ sudo add-apt-repository ppa:team-xbmc/ppa
$ sudo apt update
$ sudo apt install kodi
Note: ppa:team-xbmc/ppa is for the final release versions.  If you want a beta/release-candidate build (as I did for this installation) just switch ppa:team-xbmc/ppa to ppa:team-xbmc/unstable.

When the final version is released, you can switch to the stable build:

$ sudo add-apt-repository -r ppa:team-xbmc/unstable
$ sudo add-apt-repository ppa:team-xbmc/ppa
$ sudo apt update
$ sudo apt upgrade

ALSA, PulseAudio, TrueHD, DTS-HD MA

From what I can tell not much has changed in this aspect of the guide.  You can use PulseAudio directly with Kodi now, but you won't get TrueHD or DTS-HD MA passthrough support.  And your streams are all processed on-system instead of being sent to your receiver for processing.  So we'll continue to drop down to ALSA instead.

We use a custom XSession to accomplish this.  Which means we log in directly to Kodi instead of logging in to a desktop and running Kodi as an application.

Create our custom session launcher:

$ nano ~/kodi_custom_session_launcher

Paste in:

#!/bin/bash
# Kill PulseAudio so KODI will use ALSA for proper passthrough support
echo autospawn = no > ~/.config/pulse/client.conf
killall pulseaudio
# Start KODI
kodi-standalone
# Restore Pulse Audio
rm ~/.config/pulse/client.conf
pulseaudio --start

Make the launcher executable:

$ chmod +x ~/kodi_custom_session_launcher

Now create the custom XSession entry:

$ sudo nano /usr/share/xsessions/Kodi_ALSA.desktop

And paste in:

[Desktop Entry]
Name=Kodi with ALSA
Comment=This session will start KODI Media Center
Exec=/home/kyle/kodi_custom_session_launcher
TryExec=/home/kyle/kodi_custom_session_launcher
Type=Application
Note: Change "kyle" to your username

Now if you log out you should be able to select "Kodi with ALSA" as a session option from your login manager.  In Mint, this is accomplished by clicking the circle to the right of the user name.

Kodi Configuration

Note: Previously I had to workaround a bug with 24p audio/video synchronization.  That's no longer necessary.

I setup some stuff in Kodi's advanced settings file to disable the splash screen, hide the ext4 file system's "lost+found" directories, and increase the network streaming buffer.

Create the file:

$ nano ~/.kodi/userdata/advancedsettings.xml

And paste in:

<?xml version="1.0" encoding="UTF-8"?>
<advancedsettings>
  <splash>false</splash>
  <video>
    <excludefromlisting>
      <regexp>lost\+found</regexp>
    </excludefromlisting>
    <excludefromscan>
      <regexp>lost\+found</regexp>
    </excludefromscan>
    <excludetvshowsfromscan>
      <regexp>lost\+found</regexp>
    </excludetvshowsfromscan>
  </video>
  <network>
    <cachemembuffersize>15728640</cachemembuffersize>
  </network>
</advancedsettings>

NUC's Remote Control IR Receiver

To use the NUC's built-in IR receiver we need to install the ir-keytable utility:

$ sudo apt install ir-keytable

Then we define the keytable we need for the Onkyo RC-764M remote using the Xbox keycode 33003.  Create the file:

$ sudo mkdir /etc/rc_keymaps
$ sudo nano /etc/rc_keymaps/onkyo_rc-764m_nec_33003

And paste in:

# table onkyo_rc-764m_nec_33003, type: NEC
# Using Onkyo Remote Code 33003
# Code mappings match same buttons when using Original Xbox Dongle Remote Code
# ScanCode LIRC_KEY # Remote button text
# LIRC_KEY is modified to get correct action in XBMC using LIRC-in-kernel fake-keyboard actions

0x2d2d3a KEY_I #Display
0x2d2d59 KEY_LEFT #Left
0x2d2d5a KEY_RIGHT #Right
0x2d2d47 KEY_UP #Up
0x2d2d48 KEY_DOWN #Down
0x2d2d4a KEY_C #Guide/Top Menu -- Context Menu
0x2d2d4b KEY_ESC #Prev CH/Menu
0x2d2d45 KEY_BACK #Return
0x2d2d56 KEY_O #Setup -- Codec Info
0x2d2d58 KEY_ENTER #Enter
# UNUSED 0x2d2d4f #Audio
0x2d2d35 KEY_COMMA #Skip Left
0x2d2d34 KEY_PERIOD #Skip Right
0x2d2d32 KEY_R #Rewind
0x2d2d33 KEY_F #Fastforward
0x2d2d31 KEY_P #Play
0x2d2d38 KEY_SPACE #Pause
0x2d2d39 KEY_X #Stop
0x2d2d3b KEY_1 #1
0x2d2d3c KEY_2 #2
0x2d2d3d KEY_3 #3
0x2d2d3e KEY_4 #4
0x2d2d3f KEY_5 #5
0x2d2d40 KEY_6 #6
0x2d2d41 KEY_7 #7
0x2d2d42 KEY_8 #8
0x2d2d43 KEY_9 #9
0x2d2d44 KEY_0 #0
# UNUSED 0x2d2d4e #+10
# UNUSED 0x2d2d46 #CLR
# UNUSED 0x2d2d7c #Search
# UNUSED 0x2d2d7d #Repeat
# UNUSED 0x2d2d7f #Random
# UNUSED 0x2d2d7e #Play Mode

Now configure a systemd service to load the keytable at boot.  Create the service file:

$ sudo nano /etc/systemd/system/ir_receiver.service

And paste in:

[Unit]
Description=Configure the IR Receiver for the desired keytable

[Service]
Type=oneshot
ExecStart=/usr/bin/ir-keytable -c -p NEC -w /etc/rc_keymaps/onkyo_rc-764m_nec_33003

[Install]
WantedBy=multi-user.target

ExecStart needs the absolute path to the ir-keytable executable.  Here's what the command options do:  "-c" clears the existing keytable.  "-p NEC" puts the receiver in NEC mode. "-w /etc/rc_keymaps/onkyo_rc-764m_nec_33003" loads our custom keytable.

And enable the new service:

$ sudo systemctl enable ir_receiver.service
Change Note:
Previously I had a custom script that would unload and reload the nuvoton-cir kernel module.  That doesn't appear to be needed anymore.  Maybe it never was.

That script also used to run via rc.local.  That is no longer preferred and we use the systemd service instead

Screen Tearing

I have not seen any screen tearing yet, so I don't think this workaround is needed anymore.

Success

Now Kodi is up and running and everything is grand.

Bonus: Logitech Media Server

I also run Logitech Media Server for the fleet of Squeezebox Radios in the house.  Last time I set up a repository which kept installing updates and clobbering my configuration.  This time I just installed directly from a DEB file.

The information for LMS is a mess.  Lots of out-of-date information and lack of clarity on recommended approaches.  The main place to start is the Wiki page for Debian Packages (Mint is a derivative of Ubuntu which is a derivative of Debian).

One of the links on that page will take you to a package repository where you can download the latest DEB package (currently 7.9.2).  I grabbed the Debian amd64 package and installed it with:

$ sudo apt install ./logitechmediaserver_7.9.2~1545144292_amd64.deb

Rhythmbox sync error

There is very little information available on the Internet regarding troubleshooting music sync errors in Rhythmbox.  I was getting a "could not open resource for writing" error when trying to sync music.  I finally tracked down the issue.  One issue, anyway, I'm sure this can happen for myriad reasons.  In this case the same file existed in 2 locations within my music folder structure.  When syncing to the phone the file names/directories are normalized.  When the 2nd file was attempting to sync, the file already existed on the phone and the sync process would crash.  By removing the duplicate file from the computer the sync process continued successfully.

 

I'm sticking this next part here so I don't have to go digging around the Internet again in the future.

Unrelated to the file crash, but related to syncing music via Rhythmbox: to sync to an abitrary device (in my case, an SD card), place a file called ".is_audio_player" in the root directory of the device.  In that file I placed this text:

audio_folders=music/
playlist_path=playlists/
folder_depth=2
output_formats=audio/mpeg,audio/mp4,audio/aac,application/ogg,audio/x-ms-wma

Then Rhythmbox will detect it as a "sync-able" location.  You may have to close/re-open Rhythmbox and possibly umount/remount the device.

Home Board

Okay, "Home Board" is a dumb name, but I don't know what else to call it.  Now that we have that out of the way, let's talk about this cool thing I built.

This is a 7.5" e-ink display mounted inside a picture frame.  It's hooked up to a Raspberry Pi and updates the weather and calendar information every 15 minutes.  During "special events" it displays an additional celebration message (see example below).

This is a product I've wanted for a long time, but no one made such a thing as far as I could find.  So I finally decided to make it myself.

As you can see, the back is a bit of a mess; but it's all attached, so you only have to run the power cord.

It would be cleaner if I were using a newer Raspberry Pi. The display comes with a "hat" (zip-tied to the frame stand in this picture) that fits directly on the GPIO pins of the newer Raspberry Pi.  It doesn't fit on the version 1 (which I'm using here), so I had to use the provided multi-colored wires and connect the pins myself.

Also, the newer RPis use microSD cards that don't hang over the edge of the case (behind the power connectors).  And they have built-in Wi-Fi so there'd be no additional dongle (the blue glow at the bottom).

The 7.5" screen was the largest e-ink display I could find.  Someone used to make a 10.2" one, but it appears to be discontinued.  The refresh rate is terrible (about 15 seconds to change images, with lots of flashing throughout).  But for my purposes that's fine.  I'm only updating it every 15 minutes.

Here's a sample image of a birthday display:

I wanted a e-ink display for 2 reasons.  The first is that it doesn't glow, so being on all night isn't annoying. And the second is that it's super low power.  Power is only needed while updating the display.  It pulls its power from the Raspberry Pi, which, at full draw, maxes out at ~2 watts.  Which means, assuming some loss in the power adapter, is less than $5 a year (I'm pretty sure I did that math right).

It's awesome.

Parts

  1. Waveshare 7.5 inch e-ink 3-color display with Raspberry Pi connector.
  2. Raspberry Pi with case and power supply (I'm using a version 1, but the display works with 1, 2, or 3).
  3. 5x7" Picture frame
  4. Some miscellaneous mounting hardware to attach Pi to back of frame

The total cost of hardware is about $125 (display, RPi, SD card, case, power supply, cord, frame, mounting hardware).

Software

  1. Weather Underground API (low-volume developer key is free)
  2. Google Calendar Python API
  3. Waveshare driver to interact with the display (included in my code, below)
  4. My custom written Python application that pulls the data together, generates the image, and sends it to the display.

Understanding Meltdown

I've been trying to understand the Meltdown vulnerability that's been in the news lately (a vulnerability in Intel's CPU design allowing an attacker to obtain access to any data in memory on the system).  I understand it at a high level, but every time I've tried to dive into the details to understand an example it falls apart on me.  So I'm going to write this to force myself to fully dissect the parts I'm missing and maybe help someone else in the same boat.

This is not a post intended for a general audience.  I don't expect it will be meaningful or useful to anyone that doesn't already understand programming to some degree.

Eben Upton has a great write up over at RaspberryPi.org which will be the basis of my post.  I'm not going to recreate his work, but instead I'm going to dive into greater detail starting at "Putting it all together".

We start with his pseudocode:

t = a+b
u = t+c
v = u+d
if v:
   w = kern_mem[address]   # if we get here, fault
   x = w & 0b100           # * Modified, See Note
   y = user_mem[x]
* Modification Note:
The original was "x = w&0x100" which I've replaced with "x = w & 0b100".  0x100 is hexadecimal shorthand for the binary 000100000000.  I'm going to use an 8-bit example, so I'm replacing it with 0x4, since my example will only use binary I rewrote it to 0b100.  It is irrelevant to the method of the attack, only changed for convenience.

For those of us that spend our time on higher-level programming languages (like Java, Groovy, Python, JavaScript, etc.) the bit-twiddling needs a little more detail.  That detail is the remainder of my post.

Let's suppose we live in a 8-bit world for this example (mainly so I don't have to write out really long numbers that are irrelevant to the point I'm making).  In our 8-bit world each of our memory locations holds 8-bits.

Now, let's dissect Upton's pseudocode staring inside the "if":

w = kern_mem[address]   # if we get here, fault

This finds the 8-bits contained at "address" in a privileged part of the memory which we shouldn't be able to access, here called "kern_mem".

When the CPU sees us attempt to use that data, it will stop us (i.e., "if we get here, fault").  The crux of this vulnerability is that the CPU will fetch this information for us even though we're not allowed to see it; later it will realize we're not allowed to see it and stop us.  But we do something clever which lets us know what is in that memory even though we never saw it.

Those 8-bits from memory location kern_mem[address] are assigned to the variable "w", let's suppose those bits are 01010101.

w == 01010101 # A Number we're not allowed to see
-----
x = w & 0b100

This is a "masking" operation (think masking-tape when painting).  0b100 is the mask, which is shorthand for 00000100.  This line will "mask" out everything except 1 bit of "w".  The result will always either be 00000000 or 00000100; note that this is either all zeroes or the same value as the mask.  Since both the mask and "w" have 1 as the 3rd bit, the resulting value, in our example, will be 00000100 and assigned to the variable "x".

w == 01010101 # A Number we're not allowed to see
x == 00000100 # A single bit from that number
----
y = user_mem[x]

Now we're going to get the 8-bits contained at "x" in a piece of memory we are allowed to access, here called "user_mem".  "x" is the single bit from the-number-we-cannot-see.  In this case we'll get the 8-bits located at user_mem[00000100] and assign those 8-bits to the variable "y".

We don't care at all what the 8-bits from that location in memory actually are.  The important thing is that the memory system went and got them for us from main memory and loaded them into a local cache.  This process may have taken, say, 100ns.  Next time I ask for the 8-bits in user_mem[00000100] the memory system will say "Oh, I already have that in cache, here ya go" and it will only take, say, 3ns.  Keep this in mind.

w == 01010101 # A Number we're not allowed to see
x == 00000100 # A single bit from that number
y == we_dont_care # Cached value of user_mem[00000100]

These 3 things happen before the CPU realizes we're not allowed to see "w".  Once it makes that realization, it undoes the work so that "w", "x", and "y" no longer have these values so that we can't get to them (effectively at least).

So what good does it do us as an attacker if we can't actually get that data in "w" that we tried to access?

The memory cache still has user_mem[00000100] loaded in to it!

After tricking the CPU into doing this work for me I attempt to access user_mem[00000100].  I know to access user_mem[00000100] because 00000100 was the mask I chose (0b100).  I don't care at all what value is actually stored at user_mem[00000100].  I only care how long it takes to access: I note the current time, access the memory location, and then see how much time has passed.

If it takes ~3ns to access that memory, it must have been in the cache.  It would only be in the cache if "x" had been 00000100.  "x" would only have been 00000100 if the 3rd bit of "w" was 1.

I now know that "w" looks like ?????1??.  That was a lot of work for just a little bit of information (pun intended).  But CPUs are quick and this can all be happening without you being aware of it.  So, now let's repeat the process, but this time we'll change our mask:

w == 01010101 # A Number we're not allowed to see
-----
x = w & 0b10

The mask has been moved over one bit.  Because the 2nd bit of "w" is 0, "x" holds the 8-bits 00000000.

w == 01010101 # A Number we're not allowed to see
x == 00000000 # A single bit from that number
----
y = user_mem[x]

This time we get the 8-bits located at user_mem[00000000] loaded in to the cache.

w == 01010101 # A Number we're not allowed to see
x == 00000000 # A single bit from that number
y == we_dont_care # Cached value of user_mem[00000000]

This time the mask was 00000010, so we time how long it takes us to access user_mem[00000010].  This time it takes ~100ns, by which we determine that it must not have been in the cache.  That could only be true if "x" had been 00000000.  "x" could only have been 00000000 if the 2nd bit of "w" had been 0.

Now we know that "w" looks like ?????10?.  Keep doing this over and over again and we can read any data we like, we just have to piece it together.

Is it not a strange fate that we should suffer so much fear and doubt for so small a thing? So small a thing!

-- Boromir, "The Fellowship of the Ring"

Like Sauron's One Ring, this truly is a small thing, but will bring about much pain and anguish.

One [Flaw] to bring them all and in the darkness bind them.

Undermining the Credibility of an Investigation - A Game-Theoretic Analysis

Let's suppose you were the subject of a serious criminal investigation.  Further suppose you were also a prominent and influential public figure.  You know a priori whether there's anything damning that the investigation may find.  Should you choose to use your influence to affect the credibility of the investigation?  Should you bolster the credibility or undermine it?  Let's take a game-theoretic approach.

Like almost all game theory analyses we'll construct a payoff matrix to guide our analysis.  I suggest one axis capture the eventual outcome of the investigation: evidence of wrongdoing found (guilty) vs. no evidence of wrongdoing found (innocent).  The other axis will capture the subject's three possible actions regarding using their influence: bolster credibility (bolster), do nothing (null), undermine credibility (undermine).

Payoff matrix for subject using influence to affect credibility of investigation - Empty
Bolster Null Undermine
Innocent
Guilty

We now need to consider each possibility in the matrix and assign a relative payoff.  The payoff value represents the utility of the scenario to the subject, that is, how much does the subject benefit based on the scenario represented by each cell.

I don't think it's particularly controversial to argue that any "Innocent" outcome will be good for the subject.  Better if the credibility has been bolstered, but slightly worse if the credibility is undermined.

Payoff matrix for subject using influence to affect credibility of investigation - Partial
Bolster Null Undermine
Innocent 20 10 7
Guilty

Again, it shouldn't be controversial to assume that a "Guilty" outcome will be bad for the subject.  Worse if the credibility is bolstered, but slightly better if the credibility is undermined.

Payoff matrix for subject using influence to affect credibility of investigation - Complete
Bolster Null Undermine
Innocent 20 10 7
Guilty -20 -10 -7

At a global view, it seems like the only reason to actively undermine the credibility of the investigation is if you believe the outcome will be "Guilty" as it will increase your utility.  That should be concerning to anyone paying attention to current U.S. politics.

I think there is one potential argument for modifying the "Undermine" payoffs.  If the undermining is an attack on the biases and motivations of the investigation, the supporters of the subject may see an "Innocent/Undermine" outcome as better than "Innocent/Null" because "even the biased investigation couldn't find anything."  A similar argument could be made about the "Guilty/Undermine" payoff.  The increased nuance becomes important if you think that the subject's actions are more directly tuned to either the supporters or opposers.

Payoff matrix for subject using influence to affect credibility of investigation - Supporters/Opposers
Bolster Null Undermine
Supporters Opposers
Innocent 20 10 14 0
Guilty -20 -10 0 -14

These supporter/opposer payoffs are probably up for much debate, but I think this is probably a good ballpark.

With an "Innocent/Undermine" outcome, opposers will use the attacks on the credibility of the investigation against the subject.  But, supporters will see it as stronger evidence of innocence ("even the biased investigation couldn't find anything").

With a "Guilty/Undermine" outcome, supporters will see it as "proof" that the investigation was biased and not valid.  Opposers will see it as an attempt to evade justice.

What's interesting is if the subject cares only about supporters then the only better possible outcome than undermining the investigation is to bolster an investigation that finds the subject innocent.  If the subject, knowing a priori the truth of their actions, believes that the likelihood of the investigation concluding "Innocence" is almost zero and cares most about their supporters' response then undermining the investigation becomes overwhelmingly the best action to take.

Does the President care so little about those who oppose him that he's willing to take another hit from them in the event that the Mueller investigation finds nothing?  Or is he expecting the investigation to find evidence of wrong-doing and he's laying the groundwork to salvage the only group possible?  Or is my analysis completely wrong?