Fedora security Planet

One Week With KDE Plasma Workspaces 6 on Fedora 40 Beta (Vol. 1)

Posted by Stephen Gallagher on April 03, 2024 11:41 PM

Why am I doing this?

As my readers may be aware, I have been a member of the Fedora Engineering Steering Committee (FESCo) for over a decade. One of the primary responsibilities of this nine-person body is to review the Fedora Change Proposals submitted by contributors and provide feedback as well as being the final authority as to whether those Changes will go forth. I take this responsibility very seriously, so when this week the Fedora KDE community brought forth a Change Proposal to replace GNOME Desktop with KDE Plasma Workspaces as the official desktop environment in the Fedora Workstation Edition, I decided that I would be remiss in my duties if I didn’t spend some serious time considering the decision.

As long-time readers of this blog may recall, I was a user of the KDE desktop environment for many years, right up until KDE 4.0 arrived. At that time, (partly because I had recently become employed by Red Hat), I opted to switch to GNOME 2. I’ve subsequently continued to stay with GNOME, even through some of its rougher years, partly through inertia and partly out of a self-imposed responsibility to always be running the Fedora/Red Hat premier offering so that I could help catch and fix issues before they got into users’ and customers’ hands. Among other things, this led to my (fairly well-received) series of blog posts on GNOME 3 Classic. As it has now been over ten years and twenty(!) Fedora releases, I felt like it was time to give KDE Plasma Workspaces another chance with the release of the highly-awaited version 6.0.

How will I do this?

I’ve committed to spending at least a week using KDE Plasma Workspaces 6 as my sole working environment. This afternoon, I downloaded the latest Fedora Kinoite installer image and wrote it to a USB drive.1 I pulled out a ThinkPad I had lying around and went ahead with the install process. I’ll describe my setup process a bit below, but (spoiler alert) it went smoothly and I am typing up this blog entry from within KDE Plasma.

What does my setup look like?

I’m working from a Red Hat-issued ThinkPad T490s, a four-core Intel “Whiskey Lake” x86_64 system with 32 GiB of RAM and embedded Intel UHD 620 graphics. Not a powerhouse by any means, but only about three or four years old. I’ve wiped the system completely and done a fresh install rather than install the KDE packages by hand onto my usual Fedora Workstation system. This is partly to ensure that I get a pristine environment for this experimen and partly so I don’t worry about breaking my existing system.

Thoughts on the install process

I have very little to say about the install process. It was functionally identical to installing Fedora Silverblue, with the minimalist Anaconda environment providing me some basic choices around storage (I just wiped the disk and told it to repartition it however it recommends) and networking (I picked a pithy hostname: kuriosity). That done, I hit the “install” button, rebooted and here we are.

First login

Upon logging in, I was met with the KDE Welcome Center (Hi Konqi!), which I opted to proceed through very thoroughly, hoping that it would provide me enough information to get moving ahead. I have a few nitpicks here:

First, the second page of the Welcome Center (the first with content beyond “this is KDE and Fedora”) was very sparse, saying basically “KDE is simple and usable out of the box!” and then using up MOST of its available screen real estate with a giant button directing users to the Settings app. I am not sure what the goal is here: it’s not super-obvious that it is a button, but if you click on it, you launch an app that is about as far from “welcoming” as you can get (more on that later). I think it might be better to just have a little video or image here that just points at the settings app on the taskbar rather than providing an immediate launcher. It both disrupts the “Welcome” workflow and can make less-technical users feel like they may be in over their heads.

<figure class="wp-block-image size-large"></figure>

I actually think the next page is a much better difficulty ramp; it presents some advanced topics that they might be interested in, but it doesn’t look quite as demanding of them and it doesn’t completely take the user out of the workflow.

<figure class="wp-block-image size-large"></figure>

Next up on the Welcome Center was something very welcome: an introduction to Discover (the “app store”). I very much like this (and other desktop environments could absolutely learn from it). It immediately provides the user with an opportunity to install some very popular add-ons.2

<figure class="wp-block-image size-large"></figure>

The next page was a bit of a mixed bag for me. I like that the user is given the option to opt-in to sharing anonymous user information, but I feel like the slider and the associated details it provided are probably a bit too much for most users to reasonably parse. I think this can probably be simplified to make it more approachable (or at least bury the extra details behind a button; I had to extend the window from its default size to get a screenshot).

<figure class="wp-block-image size-large"></figure>

At the end of the Welcome Center was a page that gave me pause: a request for donations to the KDE project. I’m not sure this is a great place for it, since the user hasn’t even spent any time with the environment at all yet. It seems a bit too forwards with asking for donations. I’m not sure where a better place is, but getting begged for spare change minutes after installing the OS doesn’t feel right. I think that if we were to make KDE the flagship desktop behind Fedora Workstation, this would absolutely have to come out. I think it gives a bad first impression. I think a far better place to leave things would be the preceding page:

<figure class="wp-block-image size-large"></figure>

OK, so let’s use it a bit!

With that out of the way, I proceeded to do a bit of setup for personal preferences. I installed my preferred shell (zsh) and some assorted CLI customizations for the shell, vi, git, etc. This was identical to the process I would have followed for Silverblue/GNOME, so I won’t go into any details here. I also have a preference for touchpad scrolling to move the page (like I’m swiping a touch-screen), so I set that as well. I was confused for a bit as it seemed that wasn’t having an effect, but I realized I had missed that “touchpad” was a separate settings page from “mouse” and had flipped the switch on the wrong devices. Whoops!

In the process of setting things up to my liking, I did notice one more potential hurdle for newcomers: the default keyboard shortcuts for working with desktop workspaces are different from GNOME, MacOS and Windows 11. No matter which major competitor you are coming from, this will cause muscle-memory stumbles. It’s not that any one approach is better than another, but the fact that they are all completely different makes me sigh and forces me to think about how I’m interacting with the system instead of what I want to do with it. Unfortunately, KDE did not make figuring this out easy on me; even when I used the excellent desktop search feature to find the keyboard shortcut settings, I was presented by a list of applications that did not clearly identify which one might contain the system-wide shortcuts. By virtue of past experience with KDE, I was able to surmise that the KWin application was the most likely place, but the settings app really didn’t seem to want to help me figure that out. Then, when I selected KWin, I was presented with dozens of pages of potential shortcuts, many of which were named similarly to the ones I wanted to identify. This was simply too many options with no clear way to sort them. I ended up resorting to trying random combinations of ctrl, alt, meta and shift with arrow keys until I eventually stumbled upon the correct set.

Next, I played around a bit with Discover, installing a pending firmware update for my laptop (which hadn’t been turned on in months). I also enabled Flathub and installed Visual Studio Code to see how well Flatpak integration works and also for an app that I know doesn’t natively use Wayland. That was how I discovered that my system had defaulted to a 125% fractional scaling setup. In Visual Studio Code, everything looked very slightly “off” compared to the rest of the system. Not in any way I could easily put my finger to, until I remembered how badly fractional scaling behaved on my GNOME system. I looked into the display settings and, sure enough, I wasn’t at an integer scaling value. Out of curiosity, I played around with the toggle for whether to have X11 apps scale themselves or for the system to do it and found that the default “Apply scaling themselves” was FAR better looking in Visual Studio Code. At the end of the day, however, I decided that I preferred the smaller text and larger available working area afforded me by setting the scaling back to 100%. That said, if my eyesight was poorer or I needed to sit further away from the screen, I can definitely see the advantages to the fractional scaling and I was very impressed by how sharp it managed to be. Full marks on that one!

I next went to play around in Visual Studio Code with one of my projects, but when I tried to git clone it, I hit an issue where it refused my SSH key. Digging in, I realized that KDE does not automatically check for keys in the default user location (~/.ssh) and prompt for their passphrases. I went ahead and used ssh-add to manually import them into the SSH keyring and moved along. I find myself going back and forth on this; on the one hand, there’s a definite security tradeoff inherent in allowing the desktop to prompt (and offer to save) the passphrase in the desktop keyring (encrypted by your login password). I decline to save mine persistently, preferring to enter it each time. However, there’s a usability tradeoff to not automatically at least launching an askpass prompt. In any case, it’s not really an issue for me to make this part of my usual toolbox entry process, but I’m a technical user. Newbies might be a bit confused if they’re coming from another environment.

I then went through the motions of getting myself signed in to the various messaging services that I use on a daily basis, including Fedora’s Matrix. Once signed in there via Firefox, I was prompted to enable notifications, which I did. I then discovered the first truly sublime moment I’ve had with Plasma Workspaces: the ephemeral notifications provided by the desktop. The way they present themselves, off to the side and with a vibrant preview window and show you a progress countdown until they vanish is just *chef’s kiss*. If I take nothing else away from this experience, it’s that it is possible for desktop notifications to be beautiful. Other desktops need to take note here.

I think this is where I’m going to leave things for today, so I’ll end with a short summary: As a desktop environment, it seems to do just about everything I need it to do. It’s customizable to the point of fault: it’s got so many knobs to twist that it desperately needs a map (or perhaps a beginner vs. expert view of the settings app). Also, the desktop notifications are like a glass of icy lemonade after two days lost in the desert.

  1. This was actually my first hiccough: I have dozens of 4 GiB thumbdrives lying around, but the Kinoite installer was 4.2 GiB, so I had to go buy a new drive. I’m not going to ding KDE for my lack of preparedness, though! ↩
  2. Unfortunately I hit a bug here; it turns out that all of those app buttons will just link to the updates page in Discover if there is an update waiting. I’m not sure if this is specific to Kinoite yet. I’ll be investigating and filing a ticket about it in the appropriate place. ↩

XZ Bonus Spectacular Episode

Posted by Josh Bressers on April 01, 2024 12:03 PM

Josh and Kurt talk about the recent events around XZ. It’s only been a few days, and it’s amazing what we already know. We explain a lot of the basics we currently know with the attitude much of these details will change quickly over the coming week. We can’t fix this problem as it stands, we don’t know where to start yet. But that’s not a reason to lose hope. We can fix this if we want to, but it won’t be flashy, it’ll be hard work.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3359-1" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/XZ_Bonus_Spectacular_Episode.mp3?_=1" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/XZ_Bonus_Spectacular_Episode.mp3</audio>

Show Notes

Episode 422 – Do you have a security.txt file?

Posted by Josh Bressers on April 01, 2024 12:00 AM

Josh and Kurt talk about the security.txt file. It’s not new, but it’s not something we’ve discussed before. It’s a great idea, an easy format, and well defined. It’s not high on many of our todo lists, but it’s something worth doing.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3351-2" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_422_Do_you_have_a_securitytxt_file.mp3?_=2" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_422_Do_you_have_a_securitytxt_file.mp3</audio>

Show Notes

Revision control and sheet music

Posted by Adam Young on March 29, 2024 03:38 PM

Musescore is a wonderful tool. It has made a huge impact on my musical development over the past couple decades. Sheet music is the primary way I communicate and record musical ideas, and Musescore the tool and musecore.com have combined to make a process that works for me and my musical needs.

I have also spent a few years writing software, and the methods that we have learned to use in software development have evolved due to needs of scale and flexibility. I would like to apply some of those lessons to how I manage sheet music. But there are disconnects.

The biggest issue I have is that I want the same core song in multiple different but related formats. The second biggest issue is that I want to be able to make changes to a song, and to collaborate with other composers in making those changes.

The Sheet music I work with is based on the western notation system. I use a fairly small subset of the overall notation system, as what I am almost always working towards is a musical arrangement for small groups. The primary use case I have is for lead sheets: a melody line and a series of chords for a single instrument. Often, this is for a horn player. I need to be able to transpose the melody line into the appropriate key and range for that particular horn: E flat for a Baritone sax, C for a Flute, B flat for a saxophone, C but in Bass clef for a Trombone.

The second use case I have is to be able to arrange a section harmonically for a set of instruments. This means reusing the melody from a lead sheet, but then selecting notes for the other instruments to play as accompaniment. Often, this can be done on piano first, and then allocation the notes the piano plays out to the single-note horns.

I also wish to make play-along recordings, using ireal pro. This uses a very small subset of the lead sheet information: really just the chords and the repeats. A more complex version could be used to build MMA versions.

When I work with a more complex arrangement, I often find that I change my mind on some aspect: I wish to alter a repeat, a chord symbol, or the set of notes in the melody line.ideally that would be reflected through all the various aspects of the score.

The musescore files are stored in an xml format developed for the program. This XML file is compressed, and the the file extension reflects this: mscz. I have a song that is 40 measures long (32 with 8 bars repeated) and no more than 2 chords per measure, no more than 8 notes per measure. The underlying document used to store this song, when transposed for 6 different instruments is 22037 lines long. This is not a document format meant to be consumed by humans.

Here is a sample of how a single note is represented:

        <Articulation name="marcatoStaccato">
          <velocity>120</velocity>
          <gateTime>50</gateTime>
          </Articulation>

Here is an example for a chord

 <Chord>
            <linkedMain/>
            <durationType>quarter</durationType>
            <Note>
              <linkedMain/>
              <pitch>74</pitch>
              <tpc>16</tpc>
              </Note>
            </Chord>

This is generated code. When software is responsible for creating more software, it will often product the output in a format that can then be consumed by another tool designed to read human readable source and convert it to binary. XML is a notoriously chatty format, and the number of lines in the Musescore file reflects that.

The “document” that we humans interface with is based on pen and paper. If I were to do this by hand, I would start with a blank page of pre-printed staff paper, and annotate on it such details as the clef, the key signature, the bar lines, the notes, and the chord symbols. This system is optimized for hand-written production, and human reading-on-the-stage consumption. This is how it is displayed on the screen as well. Why, then is the underlying file format so unfriendly?

Because file formats are based on text, and we have restricted that to very specific rules as well: Characters are represented as numeric values (ascii now unicode) and anything implying the layout on the page needs to be embedded in the document as well.

There are options for turn text into sheet music: ABC and Lilypond are both formats that do this. Why don’t I use those? I have tried in the past. But when I am writing music, I am thinking in terms of notation, not in terms of text, and they end up preventing me from doing what I need. They don’t solve the transposition or other problems as is. Perhaps the issue is that we need more tooling around one of these format, but then we return to the problem of generated code.

Once the sheet music is printed out, the options for annotating a revision is to write on the sheet music, or to edit the original source and reprinting it. In practice, both of these are done often. IN front of me on my desk is a copy of a tune where both chords and individual notes have been changed in pencil. After living with these revisions for quite some time, I eventually got them recorded back into the source file and reprinted it.

Carrying around reams of sheet music quickly becomes unfeasible. If you are in multiple groups, each of which have a large repertoire, the need to reduce the physical burden will likely lead you to an electronic solution: sheet music displayed on a tablet. However, the way that you distribute sheet music here will determine what options you have allowed for the artist to annotate corrections and instructions on the music in front of them: most PDFs don’t let you edit them, and you cannot write on a screen with a ball point pen.

As a band director, I would like to be able to note changes on a score for a particular group and automate the distribution of that change to the group.

As a band member I would like to be able to make changes to a score and have them show up when I view the score electronically. Ideally, these changes would be reflected in the ireal/MMA version that I use to practice as well as the sheet music I read.

As a collaborator, I would like to be able to submit a suggested change to a score as played by my group and have the music director be able to incorporate my suggestion into the score.

As a collaborator, I would like to be able to receive suggestions from another collaborator, and provide feedback on the suggestion if I decide not to include it as-is.

As an arranger, I would like to be able to come up with a score on piano and automate the process of converting it to a set of instruments.

As a band leader, I would like to be able to come up with a lead sheet in Musescore and automate the process of converting it to MMA and irealpro formats. I would like to be able to import the accompaniment from an irealpro or MMA format into a musescore document as a first pass for the percussion or other rhythm section arrangement.

I had long thought about an application to make it possible to work on music together with other people. At West Point we used to say Collaborate and Graduate. For this, I say:

Collaborate and Orchestrate.

Episode 421 – CISA’s new SSDF attestation form

Posted by Josh Bressers on March 25, 2024 12:00 AM

Josh and Kurt talk about the new SSDF attestation form from CISA. The current form isn’t very complicated, and the SSDF has a lot of room for interpretation. But this is the start of something big. It’s going to take a long time to see big changes in supply chain security, but we’re confident they will come.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3345-3" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_421_CISA_new_SSDF_attestation_form.mp3?_=3" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_421_CISA_new_SSDF_attestation_form.mp3</audio>

Show Notes

When to Ansible? When to Shell?

Posted by Adam Young on March 19, 2024 06:00 PM

Any new technology requires a mental effort to understand. When trying to automate the boring stuff, one decision I have to make is whether to use straight shell scripting or whether to perform that operation using Ansible. What I want to do is look at a simple Ansible playbook I have written, and then compare what the comparable shell script would look like to determine if it would help my team to use Ansible or not in this situation.

The activity is building a Linux Kernel that comes from a series of topic branches applied on top of a specific upstream version. The majority of the work is done by a pre-existing shell script, so what we mostly need to do is git work.
Here is an annotated playbook. After each play, I note what it would take to do that operation in shell.

---
- name: Build a kernel out of supporting branches
  hosts: servers
  remote_user: root
  vars:
    #defined in an external vars file so we can move ahead
    #kernel_version: 
    #soc_id: 
    test_dir: /root/testing
    linux_dir: "{{ test_dir }}/linux"
    tools_dir: "{{ test_dir }}/packaging"

  tasks:

  - name:  ssh key forwarding for gitlab
    ansible.builtin.copy:
      src: files/ssh.config
      dest: /root/.ssh/config
      owner: root
      group: root
      mode: '0600'
      backup: no
  #scp $SRCDIR/files/ssh.config $SSH_USER@SSH_HOST:/root/.ssh/ssh.config
  #ssh $SSH_USER@SSH_HOST chmod 600/root/.ssh
  #ssh $SSH_USER@SSH_HOST chown root:root /root/.ssh/ssh.config

  - name: create testing dir
    ansible.builtin.file:
      path: /root/testing
      state: directory
      #ssh $SSH_USER@SSH_HOST mkdir -p /root/testing


  - name: Install Build Tools
    ansible.builtin.yum:
      name: make, gcc, git, dwarves, openssl, grubby, rpm-build, perl
      state: latest
    #ssh $SSH_USER@SSH_HOST yum -y install make, gcc, git, dwarves, openssl, grubby, rpm-build, perl

  - name: git checkout Linux Kernel
    ansible.builtin.git:
      repo: git@gitlab.com:{{ GIT_REPO_URL }}/linux.git
      dest: /root/testing/linux
      version: v6.5
#This one is a bit more complex, as it needs to check if the repo already 
#exists, and, if so, do a pull, otherwise do a clone.

  - name: add stable stable Linux Kernel repo
    ansible.builtin.command: git remote add stable https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
    changed_when: false
    args:
      chdir: /root/testing/linux
    ignore_errors: true
#there should be and Ansible git command for adding an additional remote.  
#I could not find it, so I resported to command.  
#This is identical to running via ssh

  - name: fetch stable stable Linux Kernel repo
    ansible.builtin.command: git fetch stable
    args:
      chdir: /root/testing/linux
#Same issue as above.  This shows that, when an Ansible command is
#well crafted, it can link multiple steps into a single command, reduce the #need for an additional ssh-based command.

  - name: git checkout gen-early-patches
    ansible.builtin.git:
      repo: git@gitlab.com:{{ GIT_REPO_URL }}/packaging.git
      dest: "{{ tools_dir }}"
      version: main
#same issue as with the clone for  the Linux Kernel repository

  - name: generate early kernel patches
    ansible.builtin.shell:
      cmd: "{{tools_dir }}/git-gen-early-patches.sh {{ tools_dir }}/gen-{{ soc_id }}-{{ kernel_version }}-general.conf"
      chdir: /root/testing/linux
#One benefit to running with Ansible is that it will automatically
#wrap a shell call like this with an error check.  This cuts dowm
#on boilerplate code and the potential to miss one.

  - name: determine current patch subdir
    ansible.builtin.find:
      paths: /root/testing/linux
      use_regex: true
      #TODO build this pattern from the linux kernel version
      pattern: ".*-v6.7.6-.*"
      file_type: directory
    register: patch_directory
#This would probably be easier to do in shell:
#BUILD_CMD=$( find . -name ".*-v6.7.6-.*/build.sh" | sort | tail -1 )
#

  - ansible.builtin.debug:
      msg: "{{ patch_directory.files | last }}"

  - set_fact:
      patch_dir: "{{ patch_directory.files | last }}"

  - ansible.builtin.debug:
      msg: "{{ patch_dir.path }}/build.sh"


  - name: build kernel
    ansible.builtin.shell:
      cmd: "{{ patch_dir.path }}/build.sh"
      chdir: /root/testing/linux
#Just execute the  value of BUILD_CMD
#ssh $SSH_USER@SSH_HOST /root/testing/linux/$BUILD_CMD

So, should this one be in Ansible or shell? It is a close call. Ansible makes it hard to do shell things, and this needs a bunch of shell things. But Ansible is cleaner in doing stuff on a remote machine from a known starting machine, which is how this is run: I keep the Ansible playbook on my Laptop, connect via VPN, and run the playbook on a newly provisioned machine, or rerun it on a machine while we are in the process of updating the Kernel version, etc.

This use case does not make use of one of the primary things that Ansible is very good at doing: running the same thing on a bunch of machines at the same time. Still, it shows that Ansible is at least worth evaluating if you are running a workflow that spans two machines, and has to synchronize state between them. For most tasks, the Ansible play will be sufficient, and falling back to Shell is not difficult for most other tasks.

Cleaning a machine

Posted by Adam Young on March 19, 2024 05:10 PM

After you get something working, you find you might have missed a step in documenting how you got that working. You might have installed a package that you didn’t remember. Or maybe you set up a network connection. In my case, I find I have often brute-forced the SSH setup for later provisioning. Since this is done once, and then forgotten, often in the push to “just get work done” I have had to go back and redo this (again usually manually) when I get to a new machine.

To avoid this, I am documenting what I can do to get a new machine up and running in a state where SSH connections (and forwarding) can be reliably run. This process should be automatable, but at a minimum, it should be understood.

To start with, I want to PXE boot the machine, and reinstall the OS. Unless you are using a provisioning system like Ironic or Cobbler, this is probably a manual process. But you still can automate a good bit of it. The first step is to tell the IPMI based (we are not on Red Fish yet) BMC to boot to PXE upon the next reboot.

This is the first place to introduce some automation. All of our ipmitool commands are going to take the majority of the same parameters. So we can take the easy step of creating a variable for this command, and use environmental variables to fill in the repeated values.

export CMD_IPMITOOL="ipmitool -H $DEV_BMCIP -U $IPMI_USER -I lanplus -P $IPMI_PASS"

One benefit of this is that you can now extract the variables into an environment variable file that you source separate from the function. That makes this command reusable for other machines.

To require PXE booting on the next pass we also make use of a function that can be used to power cycle the system. Note that I include a little bit of feedback in the commands I use so that the user does not get impatient.

dev_power_on(){
        CMD_="$CMD_IPMITOOL power on"
        echo $CMD_
        $CMD_
}

dev_power_off(){
        CMD_="$CMD_IPMITOOL power off"
        echo $CMD_
        $CMD_
}
dev_power_cycle(){
        dev_power_off
        dev_power_on
        dev_power_status
}

dev_pxe(){
       CMD_="$CMD_IPMITOOL  chassis bootdev pxe" 
        echo $CMD_
        $CMD_
        dev_power_cycle
}

Once this function is executed, the machine will boot to PXE mode. What this looks like is very dependent on your setup. There are two things that tend to vary. One is how you connect to the machine in order to handle the PXE setup. If you are lucky, you have a simple interface. We have a serial console concentrator here, so I can connect to the machine using a telnet command: I get this command from our lab manager. IN other stages of life, I have had to use minicom to connect to a physical UART (serial port) to handle PXE boot configuration. I highly recommend the serial concentrator route if you can swing it.

But usually you have an IPMI based option to open the serial console. Just be ware that this might conflict with, and thus disable, a UART based way of connecting. For me, I can do this using:

$CMD_IPMITOOL sol activate

The other thing that varies is your PXE set up. We have a PXE menu that allows us to select between many different Linux distributions with various configurations. My usual preference is to do a minimal install, just enough to get the machine up and on the network accessible via SSH. This is because I will almost always do an upgrade of all packages (.deb/.rpm) on the system once it is booted. I also try to make sure I don’t have any major restrictions on disk space. Some of the automated provisioning approaches make the Root filesystem or the home filesystem arbitrarily small. For development, I need to be able to build a Linux Kernel and often a lot of other software. I don’t want to run out of disk space. A partitioning scheme that is logical for a production system may not work for me. My Ops team provides and option that has Fedora 39 Server GA + Updates, Minimal, Big Root. This serves my needs.

I tend to reuse the same machines, and thus have ssh information in the files under ~/.ssh/known_hosts. After a reprovision, this information is no longer accurate, and needs to be replaced. In addition, the newly provisioned machine will not have an ssh public key on it that corresponds with my private Key. If only they used FreeIPA…but I digress…

If I try to connect to the reprovisioned machine:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ED25519 key sent by the remote host is
SHA256:EcPh9oazsjRaC9q8fJqJc8OjHPoF4vtXQljrHJhKDZ8.
Please contact your system administrator.
Add correct host key in /home/ayoung/.ssh/known_hosts to get rid of this message.
Offending ED25519 key in /home/ayoung/.ssh/known_hosts:186
  remove with:
  ssh-keygen -f "/home/ayoung/.ssh/known_hosts" -R "10.76.111.73"
Host key for 10.76.111.73 has changed and you have requested strict checking.
Host key verification failed.

The easiest way to wipe the information is:

ssh keygen -R $DEV_SYSTEMIP

Coupling this with provisioning the public key makes sense. And, as I wrote in the past, I need to set up ssh-key forwarding for gitlab access. Thus, this is my current ssh prep function:

#Only run this once per provisioning
dev_prep_ssh(){
        ssh-keygen -R $DEV_SYSTEMIP
        ssh-copy-id -o StrictHostKeyChecking=no root@$DEV_SYSTEMIP
        ssh-keyscan gitlab.com 2>&1  | grep -v \# | ssh root@$DEV_SYSTEMIP "cat >> .ssh/known_hosts"
}

The first two could be done via Ansible as well. I need to find a better way to do the last step via Ansible (line_in_file seems to be broken by this), or to bash script it so that it is idempotent.

Episode 420 – What’s going on at NVD

Posted by Josh Bressers on March 18, 2024 12:00 AM

Josh and Kurt talk about what’s going on at the National Vulnerability Database. NVD suddenly stopped enriching vulnerabilities, and it’s sent shock-waves through the vulnerability management space. While there are many unknowns right now, the one thing we can count on is things won’t go back to the way they were.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3341-4" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_420_Whats_going_on_at_NVD.mp3?_=4" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_420_Whats_going_on_at_NVD.mp3</audio>

Show Notes

Remotely checking out from git using ssh key forwarding.

Posted by Adam Young on March 13, 2024 11:16 PM

Much of my work is done on machines that are only on load to me, not permanently assigned. Thus, I need to be able to provision them quickly and with a minimum of fuss. One action I routinely need to do is to check code out of a git server, such as gitlab.com. We use ssh keys to authenticate to gitlab. I need a way to do this securely when working on a remote machine. Here’s what I have found

Key Forwarding

While it is possible to create an ssh key for every server I use, that leads to a mess. As important, it leads to an insecure situation where my ssh keys are sitting on machines that are likely to be reassigned to another user. To perform operations on git over ssh, I prefer to use key forwarding. That involves setting up on the development host a .ssh/config file that loos like this:

Host *.gitlab.com
   ForwardAgent yes

Depending on your setup, you might find it makes sense to just copy this file over as is, which is what I do. A more flexible scheme using something that appends these entries if they are non-existent may make sense if you are using Ansible and the ssh_config module or a comparable tool.

known_host seeding

When you first ssh to a development host, there is a likelihood that it will not know about the git server host. In order to make connections without warning or errors, you need to add the remote hosts fingerprints into the ~/.ssh/know_hosts files. This one-liner can do that:

ssh-keyscan gitlab.com 2>&1  | grep -v \# | ssh $DEV_USER@$DEV_HOST  "cat >> .ssh/known_hosts"

ssh-keyscan will produce output like this:

# gitlab.com:22 SSH-2.0-GitLab-SSHD
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
# gitlab.com:22 SSH-2.0-GitLab-SSHD
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
# gitlab.com:22 SSH-2.0-GitLab-SSHD
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
# gitlab.com:22 SSH-2.0-GitLab-SSHD
# gitlab.com:22 SSH-2.0-GitLab-SSHD

So I remove the comments and just add the fingerprints.

I tried to get this to work using Ansible and the lineinfile module, but I got an error 127…not sure why.

EDIT: I have corrected it. I should have used with_items, not with_lines, and ssh_keyscan_output.stdout_lines

---
- name: Set up ssh forwarding for gitlab 
  hosts: servers
  remote_user: root

  tasks:

  - name: keyscan gitlab.com
    command: ssh-keyscan gitlab.com
    register: ssh_keyscan_output

  - name: Save key fingerprints
    ansible.builtin.lineinfile:
      path: /root/.ssh/known_hosts
      line: "{{ item }}"
    with_items: " {{ ssh_keyscan_output.stdout_lines }}"

But something like that should be possible. When I did not first pre-seed the fingerprint, and I tried to do a git checkout over ssh, I would get this error:

 ssh root@10.76.111.74 "cd testing ;  git clone git@gitlab.com:$REMOTE_REPO "
bash: line 1: cd: testing: No such file or directory
Cloning into 'kernel-tools'...
Host key verification failed.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

I saw a comparable error over Ansible. The solution was to run the one liner I posted above.

EDIT: One thing I did not make expliciti is that you need to enable ssh forwarding in your ssh command:

        ssh $DEV_USER@$DEV_SYSTEMIP -A

Episode 419 – Malicious GitHub repositories

Posted by Josh Bressers on March 11, 2024 12:00 AM

Josh and Kurt talk about an attack against GitHub where attackers are creating malicious repositories then artificially inflating the number of stars and forks. This is really a discussion about how can we try to find signal in all the noise of a massive ecosystem like GitHub.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3336-5" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_419_Malicious_GitHub_repositories.mp3?_=5" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_419_Malicious_GitHub_repositories.mp3</audio>

Show Notes

Episode 418 – Being right all the time is hard

Posted by Josh Bressers on March 04, 2024 12:00 AM

Josh and Kurt talk about recent stories about data breaches, flipper zero banning, and realistic security. We have a lot of weird challenges in the world of security, but hard problems aren’t impossible problems. Sometimes we forget that.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3331-6" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_418_Being_right_all_the_time_is_hard.mp3?_=6" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_418_Being_right_all_the_time_is_hard.mp3</audio>

Show Notes

Episode 417 – Linux Kernel security with Greg K-H

Posted by Josh Bressers on February 26, 2024 12:10 AM

Josh and Kurt talk to GregKH about Linux Kernel security. We most focus on the topic of vulnerabilities in the Linux Kernel, and what being a CNA will mean for the future of Linux Kernel security vulnerabilities. The future of Linux Kernel security vulnerabilities is going to be very interesting.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3325-7" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_417_Linux_Kernel_security_with_Greg_K-H.mp3?_=7" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_417_Linux_Kernel_security_with_Greg_K-H.mp3</audio>

Show Notes

Anatomy of a Jam Performance

Posted by Adam Young on February 20, 2024 10:53 PM

My Band, The Standard Deviants, had a rehearsal this weekend. As usual, I tried to record some of it. As so often happens, our best performance was our warm up tune. This time, we performed a tune called “The SMF Blues” by my good friend Paul Campagna.

<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio">
<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" frameborder="0" height="329" src="https://www.youtube.com/embed/ZWs9G1dTfJA?feature=oembed" title="SMF Blues" width="584"></iframe>
</figure>

What is going on here? Quite a bit. People talk about Jazz as improvisation, but that does not mean that “Everything” is made up on the spot. It takes a lot of preparation in order for it to be spontaneous. Here are some of the things that make it possible to “just jam.”

Blues Funk

While no one in the band besides me knew the tune before this session, the format of the tune is a 12 bar blues. This is probably the most common format for a jam tune. A lot has been written on the format elsewhere, so I won’t detail here. All of the members of this group know a 12 bar blues, and can jump in to one after hearing the main melody once or twice.

The beat is a rock/funk beat set by Dave, our Drummer. This is a beat that we all know. This is also a beat that Dave has probably put 1000 hours into playing and mastering in different scenarios. Steve, on Bass, has played a beat like this his whole career. We all know the feel and do not have to think about it.

This song has a really strong turn around on the last two bars of the form. It is high pitched, repeated, and lets everyone know where we are anchored in the song. It also tells people when a verse is over, and we reset.

Signals

The saxophone plays a lead role in this music, and I give directions to the members of the band. This is not to “boss” people around, but rather to reduce the number of options at any given point so that we as a unit know what to do. Since we can’t really talk in this scenario, the directions have to be simple. There are three main ways I give signals to the band.

The simplest is to step up an play. As a lead instrument, the saxophone communicates via sound to the rest of the band one of two things; either we are playing the head again, or I am taking a solo. The only person that really has to majorly change their behavior is Adam 12 on Trombone. Either he plays the melody with me or he moves into a supporting role. The rest of the band just adjusts their energy accordingly. We play louder for a repetition of the head, and they back off a bit for a solo.

The second way I give signals to the band is by direct eye contact. All I have to do is look back at Dave in the middle of a verse to let him know that the next verse is his to solo. We have played together long enough that he knows what that means. I reinforce the message by stepping to the side and letting the focus shift to him.

The third way is to use hand gestures. As a sax player, I have to make these brief, as I need two hands to play many of the notes. However, there are alternative fingerings, so for short periods, I can play with just my left hand, and use my right to signal. The most obvious signal here is the 4 finger hand gesture I gave to Adam 12 that we are going to trade 4s. This means that each of us play for four measures and then switch. If I gave this signal to all of the band, it would mean that we would be trading 4s with the drums, which we do on longer form songs. Another variation of this is 2s, which is just a short spot for each person.

One of the wonderful thing about playing with this band is how even “mistakes” such as when i tried to end the tune, and no one caught the signal…and it became a bass solo that ended up perfectly placed. Steve realized we all quieted out, and that is an indication for the Bass to step up, and he did.

Practice Practice Practice

Everyone here knows their instrument. We have all been playing for many decades, and know what to do. But the horn is a harsh mistress, and she demands attention. As someone once said:

Skip a day and you know. Skip two days and your friends know. Skip three days and everyone knows.

Musical Wisdom from the ages

Adam 12 is the newest member of the band. It had been several years since he played regularly before he joined us. His first jam sessions were fairly short. We have since heard the results of the hard work that he has put in.

I try to play every day. It completes with many other responsibilities and activities in modern life. But my days seems less complete if I did not at least blow a few notes through the horn.

Listening

Music is timing. Our ears are super sensitive to changes in timing, whether at the micro level, translating to differences in pitch, or the macro level, with changes in tempo…which is just another word for time. Dave is the master of listening. He catches on to a pattern one of us it playing and he works it into his drumming constantly. Steve is the backbone of the band. Listening to the bass line tells us what we need to know about speed and location in the song. The more we play together, the more we pick up on each others cues through playing. The end effect is that we are jointly contributing to an event, an experience, a performance.

Episode 416 – Thomas Depierre on open source in Europe

Posted by Josh Bressers on February 19, 2024 12:00 AM

Josh and Kurt talk to Thomas Depierre about some of the European efforts to secure software. We touch on the CRA, MDA, FOSDEM, and more. As expected Thomas drops a huge amount of knowledge on what’s happening in open source. We close the show with a lot of ideas around how to move the needle for open source. It’s not easy, but it is possible.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3321-8" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_416_Thomas_Depierre_on_open_source_in_Europe.mp3?_=8" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_416_Thomas_Depierre_on_open_source_in_Europe.mp3</audio>

Show Notes

Swimming positions improvements

Posted by Adam Young on February 16, 2024 06:58 PM

I have been getting in the pool for the past couple of months, with a goal of completing a triathalon this summer. Today I got some pointers on things I need to improve on in my freestyle technique.

Kick

My kick needs some serious work. I am pulling almost exclusively with my arms. As Jimmy (the lifeguard and a long time swim coach) said, “You’re killing yourself.”

He had me do a drill with just a kickboard. “If your thighs are not hurting you are doing it wrong.” I focused on barely breaking the surface with my heels, pointing my toes, and keeping my legs relatively straight…only a slight bend.

Next he had me do a lap with small flippers. “You shouldn’t fell like you are fighting them.” The force you to point your toe. It felt almost too easy. We ran out of time for me to try integrating it into a regular stroke.

For weight lifting, he recommended squats.

For a sprint he recommended 3 kicks per stroke/6 per pair. For longer courses, two kicks per stroke. I think I will shoot for 2/ stroke, as I am going for 1/2 mile total.

Breathing

Improving my kick will improve my whole body position, including my breathing. It seems I am pulling my head too far out of the water, mainly because my legs are dropping. Although the opposite is true, too: pulling my head too far out of the water is causing my legs to drop. The two should be fixed together.

Arm Entry

One other swimmer at the pool that I asked for advice told me to “lead with my elbows” and then to think about entering the water “like a knife through butter”. Jimmy added that I should be reaching “long and lean.” Like a fast sailboat.

After that, the stroke should go out, and then finish in an S.

I think I need to glide more during the initial entry of the arm into the water.

Jimmy recommended a drill, either using a kickboard or a ring, and holding that out in front, and passing it from hand to hand.

Head position

I should be looking down and to the front,while the the top of my head breaks the surface.

CentOS Connect 2024 report

Posted by Alexander Bokovoy on February 13, 2024 07:25 AM

February 1st-4th I participated in two events in Brussels: CentOS Connect and FOSDEM. FOSDEM is getting closer to its quarter a century anniversary next year. With 67 mini-conferences and another 30 events around it, it is considered one of the largest conferences in Europe, any topic included. This report is about CentOS Connect.

CentOS Connect

CentOS Connect was a two-day event preceding FOSDEM. Organized by the CentOS project, it brought together contributors from multiple projects around CentOS Stream upstreams (such as Fedora Project) and downstreams (from Red Hat Enterprise Linux, AlmaLinux, Rocky Linux, and others), long-time users and community members. A lot of talks were given on both days and several special interest groups (SIGs) ran their workshops on the first day.

CentOS Integration SIG

I have attended a workshop organized by the CentOS Integration SIG. The focus of this group is to define and run integration tests around CentOS Stream delivery to the public. While CentOS Stream composes are built using the messages on how RHEL next minor version is composed after being thoroughly tested by Red Hat’s quality engineering group, there is a value in testing CentOS Stream composes by other community members independently as their use cases might differ. Right now the set of tests is defined as a t_functional suite maintained by the CentOS Core SIG but this suite is not enough for the complex scenarios.

The Integration SIG is looking at improving the situation. Two projects were present and interested in this work: RDO (RPM-based distribution of OpenStack) and RHEL Identity Management. Both teams have to deal with coordinated package deliveries across multiple components and both need to get multi-host deployments tested. RDO can be treated as a product built on top of CentOS Stream where its own RDO deliveries are installed on top of CentOS Stream images. RHEL Identity Management (IdM), on the other hand, is a part of RHEL. It is famously known as a ‘canary in the RHEL mine’ (thanks to Stephen Gallagher’s being poetic a decade ago): if anything is broken in RHEL, chances are it will be visible in RHEL IdM testing. With RHEL IdM integration scope expanding to provide passwordless desktop login support, this becomes even more important and also requires multi-host testing.

CentOS Integration SIG’s proposal to address these requirements is interesting. Since CentOS Stream compose event is independent of the tests, a proposal by Aleksandra Fedorova and Adam Samalik is to treat the compose event in a way similar to a normal development workflow. Producing CentOS Stream compose would generate a merge request of a metadata associated with it to a particular git repository. This merge request then can be reacted to by the various bots and individuals. Since CentOS Stream compose is public, it is already accessible to third-party developers to run their tests and report back the results. This way qualification of the compose promotion to CentOS Stream mirrors can be affected by all parties and will help to keep already published composes in a non-conflicting state.

Since most of the projects involved already have their own continuous integration systems, adding another trigger for those would be trivial. For RHEL IdM and its upstream components (FreeIPA, SSSD, 389-ds, Dogtag PKI, etc.) it would also be possible finally to react to changes to CentOS Stream well ahead of time too. In the past this was complicated by a relative turbulence in the CentOS Stream composes early in RHEL next minor release development time when everybody updates their code and stabilization needs a lot of coordination. I am looking forward to Aleksandra’s proposal to land in the Integration SIG’s materials soon.

Update: Aleksandra has published her proposal at the Fedora Discussion board

CentOS Stream and EPEL

Two talks, by Troy Dawson and Carl George, described the current state of EPEL repository and its future interactions with CentOS 10 Stream. Troy’s discussion was fun, as usual: a lot of statistics obtained from the DNF repository trackers shows that old habits are hard to get rid off and moving forward is a struggle to many users despite security and supportability challenges with older software. Both CentOS 7 and CentOS 8 Stream end of life dates are coming in 2024, adding enough pressure themselves to that.

There are interesting statistics from the EPEL evolution. In August 2023 at Flock to Fedora conference Troy and Carl pointed out that 727 packagers maintained 7298 packages in EPEL 7, 489 packagers handled 4968 packages in EPEL 8, and 396 packagers were handling 5985 packages in EPEL 9. Half a year later we have 7874 packages in EPEL 7, 5108 packages in EPEL 8, and 6868 packages in EPEL 9. Pace seems to pick up EPEL 9 with upcoming end of life dates for older versions. Since soon only EPEL 9 and EPEL 10 would be actively built, there are probably more packagers that would be active in them as well.

EPEL 10 is coming soon. It will bring a slight difference in package suffixes and overall reduction of complexity to packagers. It is great to see how close EPEL work tracks to ELN activities in Fedora. One thing worth noting is that every Fedora package maintainer is a potential EPEL maintainer as well because EPEL reuses Fedora infrastructure for package maintenance. Even if someone is not maintaining EPEL branches on their Fedora packages (I am not doing that myself – my packages are mostly in RHEL), it allows easy jump-in and collaboration. After all, if packages aren’t in RHEL but are in Fedora, their EPEL presence is just one git branch (and Fedora infrastructure ticket) away.

20 years of CentOS project

First day of the CentOS Connect event ended with a party to celebrate 20 years of the CentOS Project. First release (“CentOS version 2”) went out on May 14th, 2004 but since CentOS Connect is the closest big event organized by the project this year, getting a lot of contributors together to celebrate this anniversary seemed appropriate. A huge cake was presented, so big that it wasn’t possible to consume it completely during the party. It was delicious (like a lot of Belgian chocolate!) and next day coffee breaks allowed me to enjoy it a lot.

FreeIPA and CentOS project infrastructure

My own talk was originally planned to gather feedback from all projects which build on top of CentOS as they use a very similar infrastructure. CentOS Project infrastructure is shared with Fedora Project which is built around FreeIPA as a backend and Noggin as a user management frontend. I asked in advance for some feedback from Fedora, CentOS, AlmaLinux, and RockyLinux infrastructure teams and haven’t gotten that much which prompted my own investigation. It is not an easy job since most organizations aren’t really interested in telling the world details of their core infrastructure. Hope was that I’d be able to see real world usage and maybe take some lessons from it back to the development teams.

While working on my talk, we also experienced an outage in Fedora infrastructure related to the upgrade of the FreeIPA setup used there. My team has been helping Fedora infrastructure administrators so I finally got the feedback I was looking for. That led to several fixes upstream and they have recently been backported to RHEL and CentOS Stream as well. However, the overall lack of feedback is concerning – or at least I thought so.

During CentOS Connect I had the opportunity to discuss this with both AlmaLinux (Jonathan) and RockyLinux (Luis) projects’ sysadmins. “It just works” is a common response I get. Well, that’s nice to hear but what was more exciting to hear is that these projects went a bit further than we did in Fedora and CentOS Stream with their environments. Luis has published the whole RockyLinux infrastructure code responsible for FreeIPA deployment. It is based heavily on ansible-freeipa, reuses the same components we developed for Fedora Infrastructure. Rocky also runs FreeIPA tests in OpenQA instance, similarly to Fedora, and hopefully Luis would contribute more tests to cover passwordless login, already available in CentOS Stream. This would be a very welcome contribution in the light of the Integration SIG activities, helping us to test more complex scenarios community-wide. AlmaLinux infrastructure also uses ansible-freeipa but the code is not publicly available, for whatever reason. Jonathan promised to rectify this problem.

Hallway tracks

I had a number of discussions with people from all kinds of CentOS communities. FreeIPA sits at a unique position by providing secure infrastructure to run POSIX workloads and linking it with modern requirements to web authentication. Our effort to improve passwordless login to Linux environments with reuse of Kerberos to propagate authorization state across multiple machines helps to solve the ‘between the worlds’ problems. That is something that many academic institutions have noticed already and many talks I had in the hallways were related to it.

Episode 415 – Reducing attack surface for less security

Posted by Josh Bressers on February 12, 2024 12:00 AM

Josh and Kurt talk about a blog post explaining how to create a very very small container image. Generally in the world of security less is more, but it’s possible to remove too much. A lot of today’s security tooling relies on certain things to exist in a container image, if we remove them we could actually result in worse security than leaving it in. It’s a weird topic, but probably pretty important.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3316-9" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_415_Reducing_attack_surface_for_less_security.mp3?_=9" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_415_Reducing_attack_surface_for_less_security.mp3</audio>

Show Notes

Episode 414 – The exploited ecosystem of open source

Posted by Josh Bressers on February 05, 2024 12:00 AM

Josh and Kurt talk about open source projects proving builds, and things nobody wants to pay for in open source. It’s easy to have unrealistic expectations for open source projects, but we have the open source that capitalism demands.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3310-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_414_The_exploited_ecosystem_of_open_source.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_414_The_exploited_ecosystem_of_open_source.mp3</audio>

Show Notes

Vector times Matrix in C++

Posted by Adam Young on February 03, 2024 11:56 PM

The basic tool for neural networks is: vector times matrix equals vector. The first vector is your input pattern, the second is your output pattern. Stack these in a series and you have a deep neural network. The absolute simplest implementation I could find for this is in C++ using boost.

Here it is:



#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>

int main () {
    using namespace boost::numeric::ublas;
    matrix<double> m (3, 3);
    vector<double> v (3);
    for (unsigned i = 0; i < std::min (m.size1 (), v.size ()); ++ i) {
        for (unsigned j = 0; j < m.size2 (); ++ j)
            m (i, j) = 3 * i + j;
        v (i) = i;
    }


     vector<double> out1 = prod (m, v);
     vector<double> out2 = prod (v, m);

    std::cout << out1 << std::endl;
    std::cout << out2 << std::endl;


}

This is almost verbatim the sample code from Boost BLAS. Scroll down to the prod example. So now the question is, how does one go from that to a neural network? More to come.

Another question that comes to my mind is how would you optimize this if you have a vector based co-processor on your machine?

A Different Key Setup for Chords

Posted by Adam Young on January 29, 2024 01:45 AM

For my birthday last year, my family got me an accordion. Yes, I am one of those people that collect musical instruments, not for their monetary value but because I enjoy trying them out. I spent some time trying to wrap my mind and my hands around the one button chord set up on the side. I know there are masters out there that have developed a set of techniques, but for those of use from other instruments, the arraignment of notes and chords in a cycle of fifth is challenging.

It got me thinking about how else you could arrange them. This might also be somewhat inspired by guitar and bass setups, but here is what I came up with:

Start with a chromatic arrangement like this:

<figure class="wp-block-table">
G#A#C#E
GACD#
FG#BD
EGA#C#
D#F#AC
DFG#B
C#EGA#
CD#F#A
BDFG#
A#C#EG
ACD#F#
<figcaption class="wp-element-caption">Chromatic arrangement</figcaption></figure>

Assume that this is a keyboard with the bottom left nearest to you, pointing toward the ground. The Top right is pointing away and skyward. You put your pinky on A, ring finger on C, middle finger on D#, and index finger on F#. If you play those four notes, you get a diminished 7th chord.

What should be apparent from this set up is that you can play all forms of 7th chords with your pinky on the root note. To play A Major seventh, pinky on A, ring on C#, middle on E, Index on G#. If each button is a centimeter apart, Your index finger reaches at most 4 cm from lowest to highest.

To play an A augmented pinky on A. Ring on C#, Middle on F. Your index could play the root an octave up.

This same pattern would work up to F. We’d need to extend up four notes in each column to get something that would work for each chord.

Lets move our index finger to the A four notes from the bottom. From here, an Adom7 chord in second inversion could be played with pinky (P) on C#, ring(R) on E, middle(M) on G. A Maj 7moves the ring one more space up, which should still be comfortable to reach.

Lets say you have to play a I-vi-ii-V7 progression. We’ll do this in C major, both because it is well known and because it is in the middle of our keyboard. Lets say we start with the Cmaj7 in root position. Using the first letter of each finger as short hand: P-C, R-E, M-G, I-B.

<figure class="wp-block-image size-large"></figure>

(I realize now that all the images are 180 flipped from how I described it above. Just treat it like guitar tab….)

Now to Amin7, we’ll play it as I noted above: Index stays on the A. All other fingers stay in position: P-C, R-E, M-G, I-A.

<figure class="wp-block-image size-large"><figcaption class="wp-element-caption">A MINOR</figcaption></figure>

Now, to move to a Dmin7, we leave the Pinky and the Index in place (P-C, I-A) Ring finger and Middle fingers move down two keys to D and F.  Seems pretty efficient P-C, R-F, M-F I-A.

<figure class="wp-block-image size-large"></figure>

That leaves the G7. For this we want to use a third inversion, with the middle finger staying on the G. The Ring finger extends up to the B. The Pinky extends up to the D. The Ring finger extends up to the F. Again, seems pretty efficient.

<figure class="wp-block-image size-large"></figure>

I thik I ma going to do some paper prototyping here.

And with gratitude I think this is a more efficient G7 position.

<figure class="wp-block-image size-large"><figcaption class="wp-element-caption">Alternative voicing for G7.</figcaption></figure> <figure class="wp-block-image size-large"><figcaption class="wp-element-caption">My Accordion. Ain’t she pretty?</figcaption></figure>

Episode 413 – PyTorch and NPM get attacked, but it’s OK

Posted by Josh Bressers on January 29, 2024 12:00 AM

Josh and Kurt talk about an attack against PyTorch and NPM. The PyTorch attack shows the difficulty of operating a large open source project. The NPM situation continues to show the difficulty in trying to backdoor open source. Many people are watching, and it only takes one person to notice a problem and report it, and we all benefit.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3303-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_413_PyTorch_and_NPM_get_attacked_but_its_OK.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_413_PyTorch_and_NPM_get_attacked_but_its_OK.mp3</audio>

Show Notes

Episode 412 – Blame the users for bad passwords!

Posted by Josh Bressers on January 22, 2024 12:00 AM

Josh and Kurt talk about the 23andMe compromise and how they are blaming the users. It’s obviously the the fault of the users, but there’s still a lot of things to discuss on this one. Every company has to care about cybersecurity now, even if they don’t want to.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3298-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_412_Blame_the_users_for_bad_passwords.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_412_Blame_the_users_for_bad_passwords.mp3</audio>

Show Notes

Episode 411 – The security tools that started it all

Posted by Josh Bressers on January 15, 2024 12:00 AM

Josh and Kurt talk about a grab bag of old technologies that defined the security industry. Technology like SELinux, SSH, Snort, ModSecurity and more all started with humble beginnings, and many of them created new security industries.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3292-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_411_The_security_tools_that_started_it_all.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_411_The_security_tools_that_started_it_all.mp3</audio>

Show Notes

Print the line after a match using AWK

Posted by Adam Young on January 08, 2024 06:46 PM

We have an internal system for allocating hardware to developers on a short term basis. While the software does have a web API, it is not enabled by default, nor in our deployment. Thus, we end up caching a local copy of the data about the machine. The machine names are a glom of architecture, and location. So I make a file with the name of the machine, and a symlink to the one I am currently using.

One of the pieces of information I need out of this file is the IP address for ssh access. The format is two lines in the file, like this:

BMCIP
10.76.244.85
SYSTEMIP
10.76.244.65

While the SYSTEMIP is an easy regular expression match, what I need is the line after the match, and that is a little less trivial. Here is what I have ended up with (using this post as a reference).

awk 'f{print; f=0};/SYSTEMIP/{f=1}' current_dev 

Which produces the expected output:

10.76.244.65

Running a UEFI program upon reboot

Posted by Adam Young on January 08, 2024 03:51 AM

Linux is only one of the Operating Systems that our chips need to support. While some features need a complete OS for testing, we want to make sure that features are as tested as possible before we try to debug them through Linux.

My current code implements has to talk to the firmware. Thus we need to have a responder in the firmware. Testing this from Linux has to go through the entire Linux networking stack.

The developers of the firmware already have to deal with UEFI. UEFI is installed with the firmware. Since writing UEFI apps is basically like writing DOS apps (according to Ron Minnich) it is not a huge demand on our Firmware team to have them use UEFI as the basis for writing thei test code. Thus, they produced a simple app called RespTest.efi That checks that their code does what they expect it to do.

The normal process is that they boot the UEFI shell, switch to the file system, and copy up the Executable via tftp, Once it is on the system, they run it manually. After the first time the executable is leaded, the executable is persisted on the system. Thus, to run it a second or third time, after, say, a change to the firmware, can be automated from the operating system.

ls /boot/efi/
EFI  ResponderTest.efi  spinor.img

The above was executed from a Linux system running that has the efi partition mounted in /boot/efi. The RespTest.efi binary was copied up using tftp.

To see the set of UEFI boot options, we can use efibootmgr. These are mostly various flavors of PXE

efibootmgr
BootCurrent: 0001
Timeout: 10 seconds
BootOrder: 0000,0001,0002,0003,0004,0005,0006,0007,0008,0009,000A
Boot0000* UiApp	FvVol(5c60f367-a505-419a-859e-2a4ff6ca6fe5)/FvFile(462caa21-7614-4503-836e-8ab6f4662331)
Boot0001* Fedora (Samsung SSD 970 EVO Plus 250GB)	PcieRoot(0x60000)/Pci(0x1,0x0)/Pci(0x0,0x0)/NVMe(0x1,00-25-38-5A-91-51-38-0A)/HD(1,GPT,4c1510a2-110f-492f-8c64-50127bc2e552,0x800,0x200000)/File(\EFI\fedora\shimaa64.efi) File(.????????)
Boot0002* UEFI PXEv4 (MAC:0C42A15A9B28)	PcieRoot(0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/MAC(0c42a15a9b28,1)/IPv4(0.0.0.00.0.0.0,0,0){auto_created_boot_option}
...
Boot0009* UEFI HTTPv6 (MAC:0C42A15A9B29)	PcieRoot(0x0)/Pci(0x1,0x0)/Pci(0x0,0x1)/MAC(0c42a15a9b29,1)/IPv6([::]:<->[::]:,0,0)/Uri(){auto_created_boot_option}
Boot000A* UEFI Shell	FvVol(5c60f367-a505-419a-859e-2a4ff6ca6fe5)/FvFile(7c04a583-9e3e-4f1c-ad65-e05268d0b4d1)

Lets say I want to boot to the UEFI shell next time. Since that has an index of 000A, I can run the following command to tell UEFI to boot to the shell once and only once. After that it will return to the default order:

efibootmgr –bootnext 000A

Here are the first few lines of output from that command;

# efibootmgr --bootnext 000A
BootNext: 000A
BootCurrent: 0001
Timeout: 10 seconds

If I want to add an addition boot option, I can use the –create option. To tell it to boot the ResponderTest,efi executable:

efibootmgr efibootmgr --create -d /dev/nvme0n1p1 --label RespTest -l RespTest.efi

The last line of output from that command is:

Boot000B* RespTest	HD(1,GPT,4c1510a2-110f-492f-8c64-50127bc2e552,0x800,0x200000)/File(RespTest.efi)efibootmgr

If I then want to make UEFI select this option upon next boot…

# efibootmgr --bootnext 000B
BootNext: 000B
BootCurrent: 0001
Timeout: 10 seconds

Note that the executable is in /boot/efi mounted on the Linux filesystem, but that will be the EF0: in UEFI. If you wish to put something further down the tree, you can, but remember that UEFI uses reverse slashes. I think it would look something like this…but I have not tried it yet:

efibootmgr efibootmgr –create -d /dev/nvme0n1p1 –label RespTest -l EFI\\RespTest.efi

Note the double slash to avoid Linux escaping….I think this is necessary.

Episode 410 – Package identifiers are really hard

Posted by Josh Bressers on January 08, 2024 12:00 AM

Josh and Kurt talk about package identifiers. We break this down in the context of an OpenSSF response to a CISA paper on software identifications. The identifiers that get all the air time are purl, CPE, SWID, and OmniBOR. This is a surprisingly complex problem space. It feels easy, but it’s not.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3289-7" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_410_Package_identifiers_are_really_hard.mp3?_=7" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_410_Package_identifiers_are_really_hard.mp3</audio>

Show Notes

On The Lineageos User Exposure Window

Posted by Robbie Harwood on January 07, 2024 05:00 AM

Unfortunate scheduling means that LineageOS users are exposed to publicly disclosed vulnerabilities for typically nine days per month. Here's why, and what I (a user who is otherwise uninvolved in the project) think could be done to improve the situation.

Per official Android documentation:

Important: The Android Security Bulletins are published on the first Monday of each month unless that Monday falls on a holiday. If the first Monday of the month is a holiday the bulletins will be published on the following work day.

Holiday time off makes sense for human reasons, though it makes release days inconsistent. (And I assume we're talking US holidays because Google, though this isn't stated.) Adherence to this isn't great - most egregiously, something happened that resulted in a March 13, 2023 release which is probably the largest slip since August 13, 2015 (which is far back as the table goes). But I've worked in security engineering long enough to know that sometimes dates will slip, and I'm sure it's not intentional. Clerical errors like the November 2023 bulletin date are also inevitable.

But let's assume for the sake of simplicity that disclosure happens as written: on the first Monday of the month (or the following day) a bulletin is published listing the CVEs included, their type/severity, and which Android (i.e., AOSP) versions are affected. Importantly absent here are the patches for these vulnerabilities, which per the bulletin boilerplate take 2 days to appear. So what's the point of the bulletin?

In any case, this means that patches won't be available until Wednesday or Thursday. Lineage posts updates on Friday; per datestamps, these updates are built on Thursdays. This means that in order to have the security fixes (and security string) in the next Lineage update, there is less than a day's window to gather patches, backport them, post pull requests, run CI, get code review, etc., before the weekly build is made - a seemingly herculean feat. And sometime months, it won't be technically possible at all.

So since patches will not land in the next release, all users of official builds are exposed to publicly disclosed vulnerabilities for typically nine days. (I think it's 8-10, but I don't discount off-by-one, and that also relies on Lineage not slipping further; everyone's human and it does happen, especially on volunteer projects.)

Clearly, the schedule is a problem. Here are my initial thoughts on how this might be addressed:

  1. Release Lineage updates on a different day. If it takes four days to run through the backport+review+build pipelines, then plan to release on Monday. Users will still be exposed for the length of time it takes to backport+review+build.
  2. Add Lineage to the embargo list. This would mean that backport and review could take place prior to public disclosure, and so including the security fixes in the upcoming Friday update becomes doable. Users are still exposed for 2 days, but that's way better than 9. (I am not involved in the Lineage project so it's possible they already are included, but that seems unlikely given security update PRs are not usually sent on the day code becomes publicly available.)
  3. Stop the bulletin/patch desync. I cannot come up with a good reason why the security bulletin and patches are released at different times, let alone releasing the bulletin before the patches. This makes reasoning about fix availability unnecessarily complicated. However, it would probably require Google to care.
  4. Update Lineage less frequently. It seems like the least amount of work, but if, e.g., Lineage released once per month, then the day of the release could be whenever the security fixes for the month land. This is also helpful beccause it minimizes the number of times that flashing needs to occur. (But that may be a larger discussion for a different post.)

These are not mutually exclusive, either.

To close out, I need to head off something that I am quite sure will come up. Yes, I am capable of running my own custom Android builds and kernel trees. I do not want to do this, and more importantly, users who are not developers by definition cannot do it. That is to say: OTA updates and official builds are the most important versions of the project, not whatever custom stuff we make. (After all, if that weren't the case, there wouldn't be five major forks over the signature spoofing decision.)

How Did I break my Code

Posted by Adam Young on January 04, 2024 11:17 PM

Something I did in a commit broke my code. I have a git bisect that shows me the last good commit and the first bad one.

The code in question is a device driver for MCTP over PCC. MCTP is a network protocol used to have different components on a single system talk to each other. PCC is a shared buffer mechanism with a “doorbell” or register-that-triggers-an-interrupt. Another team needs to use this driver.

In looking through the output, a co-worker stated “it looks like you are sending the wrong buffer.” I suspected he was correct.

The buffers are pulled from ACPI information in a table specific to PCC, called the PCCT.

This is from the PCCT, which is common to both the good and bad run, and shows the machine (physical) addresses of the memory.


03 [Extended PCC Master Subspace]
               Base Address       = 00004000000D4004


04 [Extended PCC Slave Subspace]
               Base Address       = 00004000000D4404

Here is output data I get from a run of code from tip of tree.




[  644.338469] remap_pcc_comm_addresses outbox pcc_chan->shmem_base_addr = 4000000d4004 mapped to  ffff800080621004
[  644.348632] remap_pcc_comm_addresses inbox pcc_chan->shmem_base_addr = 4000000d4404 mapped to ffff80008061f404

[  644.338469] remap_pcc_comm_addresses outbox pcc_chan->shmem_base_addr = 4000000d4004 mapped to  ffff800080621004
[  644.348632] remap_pcc_comm_addresses inbox pcc_chan->shmem_base_addr = 4000000d4404 mapped to ffff80008061f404
 



 
[  828.014307] _mctp_get_buffer pcc_chan->shmem_base_addr = 1  ptr = 000000007f3ab582 
[  828.021950] mctp_pcc_tx buffer = ffff80008061f404

What I see is that I am sending data on the inbox address, not the outbox. So where did I swap it?

541392a553a2c2b7f741d89cff0ab8014a367299 is the first bad commit.

Lets take a look at the code in that commit. The diff shows a lot of changes in _mctp_get_buffer. Here’s what it looks like in non-diff form

static unsigned char * _mctp_get_buffer (struct mbox_chan * chan){
        void __iomem * pcc_comm_addr;
         
        struct pcc_mbox_chan * pchan = (struct pcc_mbox_chan *) chan;

        
        if (pchan == mctp_pcc_dev->out_chan){
                pcc_comm_addr =  mctp_pcc_dev->pcc_comm_outbox_addr;
        }else{
                pcc_comm_addr = mctp_pcc_dev->pcc_comm_inbox_addr;
        }
        pr_info("%s pcc_chan->shmem_base_addr = %llx  ptr = %p \n",
                        __func__, pchan->shmem_base_addr, pcc_comm_addr );
        return (unsigned char *  )pcc_comm_addr;
} 

How could this fail? Well, what if the cast from chan to pchan is bogus? If that happens, the if block will not match, and we will end up in the else block.

Why would I cast like that? Assume for a moment (as I did) that the definitions looked like this:

struct   pcc_mbox_chan {
 struct mbox_chan  chan;
}

Ignore anything after the member variable chan. This is a common pattern in C when you need to specialize a general case.

This is not what the code looks like. Instead, it looks like this:

struct   pcc_mbox_chan {
 struct mbox_chan*  chan;
}

The structure that chan points to was allocated outside of this code, and thus cannot be cast.

The else block always matched.

The reason the old code ran without crashing is it was getting a valid buffer, just not the right one. I was trying to send the “outbox” buffer, but instead sent the “inbox” buffer.

Here is the corrected version of the if block.

if (chan == mctp_pcc_dev->out_chan->mchan){
        pcc_comm_addr = mctp_pcc_dev->pcc_comm_outbox_addr;
}else if (chan == mctp_pcc_dev->in_chan->mchan){
        pcc_comm_addr = mctp_pcc_dev->pcc_comm_inbox_addr;
}
if (pcc_comm_addr){
        pr_info("%s buffer ptr = %px \n",__func__, pcc_comm_addr );
        return (unsigned char * )pcc_comm_addr;
}

What made this much harder to debug is the fact that the “real” system I was testing against had changed and I was not able to test my code against it for a week or so, and by then I had added additional commits on top of the original one. This shows the importance of testing early, testing often, and testing accurately.

To give a sense of how things got more complicated, here is the current version of the get_buffer function:

static unsigned char * _mctp_get_buffer (struct mbox_chan * chan){
        struct mctp_pcc_ndev * mctp_pcc_dev = NULL;
        struct list_head *ptr;
        void __iomem * pcc_comm_addr = NULL;
        list_for_each(ptr, &mctp_pcc_ndevs) {
                mctp_pcc_dev = list_entry(ptr,struct mctp_pcc_ndev, head);
        
                if (chan == mctp_pcc_dev->out_chan->mchan){
                        pcc_comm_addr =  mctp_pcc_dev->pcc_comm_outbox_addr;
                }else if (chan == mctp_pcc_dev->in_chan->mchan){
                        pcc_comm_addr = mctp_pcc_dev->pcc_comm_inbox_addr;
                }
                if (pcc_comm_addr){
                        pr_info("%s buffer ptr = %px \n",
                                __func__, pcc_comm_addr );
                        return (unsigned char *  )pcc_comm_addr;
                }
        }
        //TODO this should never happen, but if it does, it will
        //Oops.  Handle the error better
        pr_err("%s unable to match mctp_pcc_ndev", __func__);
        return 0;
}

Why is it now looking through a list? One of the primary changes I had to make was to move the driver from only supporting a single device to supporting multiple. Finding which buffer to get from struct mbox_chan is again going from general to specific.

This code is still in flight. The list lookup may well not survive the final cut, as there is possibly a better way to get the buffer from the original structure, but it is not clear cut. This works, and lets the unit tests continue to pass. This allows the team to make progress. It might be technical debt, but that is necessary part of a complicated development integration process.

Episode 409 – You wouldn’t hack a train?

Posted by Josh Bressers on January 01, 2024 12:00 AM

Josh and Kurt talk about how some hackers saved the day with a Polish train. We delve into a discussion about how we don’t really own anything anymore if you look around. There’s a great talk from the Blender Conference about this and how GPL makes a difference in the world of software ownership. It’s sort of a dire conversation, but not all hope is lost.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3285-8" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_409_You_wouldnt_hack_a_train_fixed.mp3?_=8" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_409_You_wouldnt_hack_a_train_fixed.mp3</audio>

Show Notes

Episode 408 – Does Kubernetes need long term support?

Posted by Josh Bressers on December 25, 2023 12:00 AM

Josh and Kurt talk about a story asking for a Kubernetes LTS. Should open source projects have LTS versions? What does LTS even mean? Why is maintaining software so hard? It’s a lively discussion all about the past, present, and future of open source LTS.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3280-9" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_408_Does_Kubernetes_need_long_term_support_fixed.mp3?_=9" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_408_Does_Kubernetes_need_long_term_support_fixed.mp3</audio>

Show Notes

Episode 407 – Should Santa use AI?

Posted by Josh Bressers on December 18, 2023 12:00 AM

It’s the 2023 Christmas Spectacular! Josh and Kurt talk about what would happen if Santa starts using AI to judge which children are naughty and nice. There’s some fun in this one, but it does get pretty real. While we tried to discuss Santa using AI, the reality is this sort of AI is coming for many of us. AI will be making decisions for all of us in the near future (if it isn’t already). While less fun than we had hoped for, it’s an important conversation.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3272-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_407_Should_Santa_use_AI.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_407_Should_Santa_use_AI.mp3</audio>

Show Notes

Episode 406 – The security of radio

Posted by Josh Bressers on December 11, 2023 12:00 AM

Josh and Kurt talk about a few security stories about radio. The TETRA:BURST attack on police radios, spoofing GPS for airplanes near Iran, and Apple including cellular radios in the macbooks. The common thread between all these stories is looking at the return on investment for security. Sometimes good enough security is fine, sometimes it’s not worth fixing certain security problems because the risk vs reward doesn’t work out.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3268-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_406_The_security_of_radio.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_406_The_security_of_radio.mp3</audio>

Show Notes

Episode 405 – Modding games isn’t cheating and security isn’t fair

Posted by Josh Bressers on December 04, 2023 12:00 AM

Josh and Kurt talk about Capcom claiming modding a game is akin to cheating. The arguments used are fundamentally one of equity vs equality. Humans love to focus on equality instead of equity when we deal with most problems. This is especially true in the world of security. Rather than doing something that has a net positive, we ignore the details and focus on doing something that feels “right”.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3263-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_405_Modding_games_isnt_cheating_and_security_isnt_fair.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_405_Modding_games_isnt_cheating_and_security_isnt_fair.mp3</audio>

Show Notes

recvfrom system call in python

Posted by Adam Young on November 27, 2023 07:21 PM

With a socket created, and a message sent, the next step in our networking journey is to receive data.

Note that I used this post to get the parameter right. Without using the ctypes pointer function I got an address error.

print("calling recvfrom")
recv_sockaddr_mctp = struct_sockaddr_mctp(AF_MCTP, 0, mctp_addr , 0, 0)
len = 2000;
rxbuf = create_string_buffer(len)
sock_addr_sz = c_int(sizeof(recv_sockaddr_mctp))
MSG_TRUNC = 0x20
rc = libc.recvfrom(sock, rxbuf, len, MSG_TRUNC, byref(recv_sockaddr_mctp), pointer(sock_addr_sz));
errno = get_errno_loc()[0]

if (rc < 0 ):
    print("rc = %d errno =  %d" % (rc, errno))
    exit(rc)

print(rxbuf.value)

From previous articles you might be wondering about these values.

AF_MCTP = 45
mctp_addr = struct_mctp_addr(0x32)

However, the real magic is the structures defined using ctypesgen. I recommend reading the previous article for the details.

While the previous two article are based on the code connect example that I adjusted and posted here, the recvfrom code is an additional call. The c code it is based on looks like this:

    addrlen = sizeof(addr);

    rc = recvfrom(sd, rxbuf, len, MSG_TRUNC,
                (struct sockaddr *)&addr, &addrlen);

Episode 403 – Does the government banning apps work?

Posted by Josh Bressers on November 27, 2023 12:00 AM

Josh and Kurt talk about the Canadian Government banning WeChat and Kaspersky. There’s a lot of weird little details in this conversation. It fundamentally comes down to a conversation about risk. It’s easy to spout nonsense about risk, but having an honest discussion about it is REALLY complicated. But the government plays by a very different set of rules.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3258-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_403_Does_the_government_banning_apps_work.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_403_Does_the_government_banning_apps_work.mp3</audio>

Show Notes

sendto system call from python

Posted by Adam Young on November 22, 2023 08:18 PM

Once we open a socket, we probably want to send and receive data across it.Here is the system call we need to make in order to send data as I wrote about in my last post:

c = sendto(sd, buf, sizeof(buf), 0,
                (struct sockaddr *)&addr, sizeof(addr));

Note the cast of the addr parameter. This is a structure with another structure embedded in it. I tried hand-jamming the structure, but the data sent across the system call interface was not what I expected. In order to make it work ,I uses a utility called ctypesgen with the header I separated out in my last post. Runing this:

ctypesgen ./spdmcli.h

generates a lot of code, much of which I don’t need. The part I do need looks like this:


__uint8_t = c_ubyte# /usr/include/bits/types.h: 38
__uint16_t = c_ushort# /usr/include/bits/types.h: 40
__uint32_t = c_uint# /usr/include/bits/types.h: 42
uint8_t = __uint8_t# /usr/include/bits/stdint-uintn.h: 24
uint16_t = __uint16_t# /usr/include/bits/stdint-uintn.h: 25
uint32_t = __uint32_t# /usr/include/bits/stdint-uintn.h: 26

# /root/spdmcli/spdmcli.h: 5
class struct_mctp_addr(Structure):
    pass

struct_mctp_addr.__slots__ = [
    's_addr',
]
struct_mctp_addr._fields_ = [
    ('s_addr', uint8_t),
]

# /root/spdmcli/spdmcli.h: 9
class struct_sockaddr_mctp(Structure):
    pass

struct_sockaddr_mctp.__slots__ = [
    'smctp_family',
    'smctp_network',
    'smctp_addr',
    'smctp_type',
    'smctp_tag',
]
struct_sockaddr_mctp._fields_ = [
    ('smctp_family', uint16_t),
    ('smctp_network', uint32_t),
    ('smctp_addr', struct_mctp_addr),
    ('smctp_type', uint8_t),
    ('smctp_tag', uint8_t),
]

# /root/spdmcli/spdmcli.h: 3
try:
    MCTP_TAG_OWNER = 0x08
except:
    pass

mctp_addr = struct_mctp_addr# /root/spdmcli/spdmcli.h: 5

sockaddr_mctp = struct_sockaddr_mctp# /root/spdmcli/spdmcli.h: 9

With those definition, the following code makes the system call with the parameter data in the right order:


mctp_addr = struct_mctp_addr(0x32) # /root/spdmcli/spdmcli.h: 16
sockaddr_mctp = struct_sockaddr_mctp(AF_MCTP, 1, mctp_addr , 5, 0x08)

p = create_string_buffer(b"Held") 
p[0] = 0x10 
p[1] = 0x82

sz = sizeof(sockaddr_mctp)
print("calling sendto")


rc = libc.sendto(sock, p, sizeof(p), 0, byref(sockaddr_mctp), sz) 
errno = get_errno_loc()[0]
print("rc = %d errno =  %d" % (rc, errno)   )

if (rc < 0 ):
    exit(rc)

print("OK")

With this Next step is to read the response.

Updated MCTP send code

Posted by Adam Young on November 22, 2023 04:26 PM

While the existing documentation is good, there are a couple things that have changed since it was originally written, and I had to make a couple minor adjustments to get it to work. Here’s the code to send a message. The receive part should work as originally published; what is important is the set of headers. I built and ran this on an AARCH64 platform running Fedora 38.

I split the code into a header and a .c file for reasons I will address in another article.

spdmcli.h

#include <stdint.h>

#define MCTP_TAG_OWNER 0x08

struct mctp_addr {
    uint8_t             s_addr;
};

struct sockaddr_mctp {
    uint16_t            smctp_family;
    uint32_t            smctp_network;
    struct mctp_addr    smctp_addr;
    uint8_t             smctp_type;
    uint8_t             smctp_tag;
}

I also coded this for spdm, not MCTP control messages. The difference is the value for addr.smctp_type

EDIT: I also added the recvfrom call to make this complete.

spdmcli.c

#include <linux/mctp.h>
#endif
#include <linux/if_link.h>
#include <linux/rtnetlink.h>

#include "stdio.h"
#include "spdmcli.h"

int main(void)
{
    struct sockaddr_mctp addr = { 0 };
    char buf[] = "hello, world!";
    int sd, rc;

    /* create the MCTP socket */
    sd = socket(AF_MCTP, SOCK_DGRAM, 0);
    if (sd < 0)
        err(EXIT_FAILURE, "socket() failed");

    /* populate the remote address information */
    addr.smctp_family = AF_MCTP;  /* we're using the MCTP family */
    addr.smctp_addr.s_addr = 0x32;   /* send to remote endpoint ID 32 */
    addr.smctp_type = 5;          /* encapsulated protocol type iSPDM = 5 */
    addr.smctp_tag = MCTP_TAG_OWNER; /* we own the tag, and so the kernel
                                        will allocate one for us */

    addr.smctp_network = 1 ;
    /* send the MCTP message */
    rc = sendto(sd, buf, sizeof(buf), 0,
                (struct sockaddr *)&addr, sizeof(addr));

    if (rc != sizeof(buf))
        err(EXIT_FAILURE, "sendto() failed");

   //EDIT: The following code recieves a message from the network and prints it to the console.
        if (rc < 0){
        err(EXIT_FAILURE, "recvfrom() failed");
    }

    printf("recv rc = %d\n",rc);        

    for (int i =0; i< rc; i++){
        printf("%x", rxbuf[i]); 

    }



    return EXIT_SUCCESS;
}

socket system call from python

Posted by Adam Young on November 21, 2023 08:37 PM

While the Python socket API is mature, it does not yet support MCTP. I thought I would thus try to make a call from python into native code. The first step is to create a socket. Here is my code to do that.

Note that this is not the entire C code needed to make network call, just the very first step.I did include the code to read errno if the call fails.

#!/usr/bin/python3
from ctypes import *
libc = CDLL("/lib64/libc.so.6")
AF_MCTP = 45
SOCK_DGRAM  = 2
rc = libc.socket (AF_MCTP, SOCK_DGRAM, 0)
#print("rc = %d " % rc)
get_errno_loc = libc.__errno_location
get_errno_loc.restype = POINTER(c_int)
errno = get_errno_loc()[0]
print("rc = %d errno =  %d" % (rc, errno)   )
print("OK")

Running this code on my machine shows success

# ./spdm.py 
rc = 3 errno =  0
OK

Episode 402 – The EU’s eIDAS regulation is a terrible idea

Posted by Josh Bressers on November 20, 2023 12:00 AM

Josh and Kurt talk about the new EU eIDAS regulation. This is a bill that will force web browsers to add root certificates based on law instead of technical merits, which is how it’s currently done. This is concerning for a number of reasons that we discuss on the show. This proposal is not a good idea.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3254-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_402_The_EUs_eIDAS_regulation_is_a_terrible_idea.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_402_The_EUs_eIDAS_regulation_is_a_terrible_idea.mp3</audio>

Show Notes

Refactoring in C: Introduce Dispatch Map

Posted by Adam Young on November 13, 2023 07:33 PM

There is a pretty common pattern in C coding that uses a Key, often an integer, to select a function to call. However, code may not start there, and there is a pretty common set of interim steps you might go to get there.

The growth is often like this:

If the logic for each case is similar and/or small, the switch statement may well be the final state. However, if the logic inside each of the case blocks gets too complex, then an common step that can be injected as soon as step 2 is to execute the refactoring of extract method except that we will call it extract function, we don’t have methods in C.

To give a concrete example, I am working with MCTP, a protocol where a message is delivered in a buffer. We take the payload of the buffer and select a specific offset to see the “type” of the message, and based on that type code, we need to perform a different operation. The Type code is the first byte of the payload, and it states what the higher level protocol is. In its current state of evolution, that can be one of three things: MCTP control messages, PLDM, or SPDM. Thus, the code evolution looks like this.

Handle the first case in the main method.

static void mctpserv_deliver(struct mbox_client * cl, void * data){
        struct mctp_pcc_packet * mpp;
        mpp  = (struct mctp_pcc_packet *)data;
        //do Simple MCTP stuff
        //send back status
}


Use an If statement to handle the error case

static void mctpserv_deliver(struct mbox_client * cl, void * data){
        struct port_handler mapping;
        struct mctp_pcc_packet * mpp;
        mpp  = (struct mctp_pcc_packet *)data;
        pr_info("%s signature = %x \n", __func__,
        (u32)mpp->pcc_header.signature);
        if (mpp->payload[0]  == MCTP_CONTROL){
                  //do Simple MCTP stuff
                  //send back success status  
        }else{
                  //send back error code
        }
 
}

Use an extended if/else clause to handle the second case

static void mctpserv_deliver(struct mbox_client * cl, void * data){
struct port_handler mapping;
struct mctp_pcc_packet * mpp;
mpp = (struct mctp_pcc_packet *)data;
pr_info(“%s signature = %x \n”, __func__,
(u32)mpp->pcc_header.signature);
if (mpp->payload[0] == MCTP_CONTROL_CODE){
//do Simple MCTP stuff
//send back success status
}else if((mpp->payload[0] == SPDM_CODE)) {
//do SPDM stuff
}else{
//send back error code
}
}

Use a switch statement to handle more than one case

static void mctpserv_deliver(struct mbox_client * cl, void * data){
        struct port_handler mapping;
        struct mctp_pcc_packet * mpp;
        mpp  = (struct mctp_pcc_packet *)data;
        pr_info("%s signature = %x \n", __func__,
        (u32)mpp->pcc_header.signature);
        switch (mpp->payload[0]){
             case MCTP_CONTROL_CODE: {
                  //do Simple MCTP stuff
                  //send back success status
             };  
             break;
             case SPDM_CODE: {
                  //do SPDM stuff        
              };
              break;
              default: 
                  //send back error code
        }
}

Extract function

void handle_mctp(struct mctp_pcc_packet * mpp){
//...
}

void handle_spdm(struct mctp_pcc_packet * mpp){
//...
}

void handle_pldm(struct mctp_pcc_packet * mpp){
//...
}


static void mctpserv_deliver(struct mbox_client * cl, void * data){
        struct port_handler mapping;
        struct mctp_pcc_packet * mpp;
        mpp  = (struct mctp_pcc_packet *)data;
        pr_info("%s signature = %x \n", __func__,
        (u32)mpp->pcc_header.signature);
        switch (mpp->payload[0]){
             case MCTP_CONTROL_CODE:  
               handle_mctp(mpp);
               break;
             case SPDM_CODE:
               handle_spdm(mpp);
               break;
            case PLDM_CODE:
               handle_pldm(mpp);
               break;
              default: 
                  //send back error code
        }
}

Note that when we extract the function, we use the same function signature. This is deliberate so we can use a function pointer in the next step without having to change the parameters passed to it. In order to define the function signature and the key used to select it, we put both inside a structure. for added type safety, use an enum to limit the values to the acceptable range.

enum MCTP_MSG_TYPE {
        MCTP_MSG_TYPE_CTRL = 0,
        MCTP_MSG_TYPE_PLDM = 1,
        MCTP_MSG_TYPE_SPDM = 5,
};
struct port_handler {
        enum MCTP_MSG_TYPE code;
        void (* handler )(struct mctp_pcc_packet * mpp);
};
struct port_handler handlers[]  = {

        {MCTP_MSG_TYPE_CTRL, handle_mctp },
        {MCTP_MSG_TYPE_PLDM, handle_pldm},
        {MCTP_MSG_TYPE_SPDM, handle_spdm}
};

One thing this example shows is why not to use the index of the array as the key; a sparse and non contiguous integer sequence means you would have a lot of wholes in that array. We need 0, 4, and 5 only.

Since our sequence is short, we can iterate through it using a linear search:

        for (int i = 0;  i <  sizeof(handlers)  / sizeof(struct port_handler )  ; i++){
                if (handlers[i].code == mpp-> payload[0]){
                        handlers[i].handler(mpp);
                        break;
                }
        }

For longer lists, it might be necessary to use a binary search. I am not going to show an example of that here, as I have not written it, and my example would certainly be buggy.

Handle a missing function

This example does not show how to handle a missing function. There are two ways I have done this: either set a boolean when the handler is called, or have the default case be an error handler. Here is the default case as a function.

void default_handler(struct mctp_pcc_packet * mpp){
        pr_info("%s unsupported protocol \n", __func__);
}
struct port_handler default_mapping = {
        MCTP_MSG_TYPE_MAX,
        default_handler,
};
static void mctpserv_deliver(struct mbox_client * cl, void * data){
        struct port_handler * mapping = &default_mapping;
        struct mctp_pcc_packet * mpp;

        pr_info("%s\n", __func__);

        mpp  = (struct mctp_pcc_packet *)data;
        pr_info("%s signature = %x \n", __func__,
        (u32)mpp->pcc_header.signature);
        pr_info("%s type code = %d \n", __func__, mpp-> payload[0] );


        for (int i = 0;  i <  sizeof(handlers)  / sizeof(struct port_handler )  ; i++){
                if (handlers[i].code == mpp-> payload[0]){
                        mapping = &handlers[i];
                        break;
                }
        }
        mapping->handler(mpp);
}

Episode 401 – Security skills shortage – We’ve tried nothing and the same thing keeps happening

Posted by Josh Bressers on November 13, 2023 12:00 AM

Josh and Kurt talk about security skills shortage. We start out on the topic of cybersecurity skills and weave our way around a number of human related problems in this space. The world of tech has a lot of weird problems and there’s not a lot of movement to fix many of them. Tech is weird and hard, and with the almost complete lack of regulation creates some of these challenges. In the world of security we need a better talent pipeline, but that takes actual efforts, not just complaining on the internet.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3250-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_401_Security_skills_shortage_Weve_tried_nothing_and_the_same_thing_keeps_happening.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_401_Security_skills_shortage_Weve_tried_nothing_and_the_same_thing_keeps_happening.mp3</audio>

Show Notes

Episode 400 – When can the government hack a victim?

Posted by Josh Bressers on November 06, 2023 12:00 AM

Josh and Kurt talk about a proposed Dutch proposal that would allow the intelligence services to hack victims of adversaries they are in the process of infiltrating. The purpose of this discussion isn’t to focus on the Dutch specifically, but rather to discuss the larger topic of government oversight. These are all very new concepts and nobody knows how things should work.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3246-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_400_When_can_the_government_hack_a_victim.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_400_When_can_the_government_hack_a_victim.mp3</audio>

Show Notes

Round Trip with MCTP over PCC

Posted by Adam Young on November 02, 2023 07:17 PM

The future Ampere System-on-a-chip that is the basis for my work has a couple of processors that are for providing system wide services, not for end users to run things on directly. One of these is called the Management Processor, or Mpro. We have to talk to one of these services from the operating system using the Management Control Transport Protocol, or MCTP, over a Platform Communication Channel (PCC).

I just sent ran a user-land program that sends a message via a socket into the operating system, via PCC, to the MPro, and got a response back.

It took a while for it to sink in. And then I raised my hands in the air and proclaimed in my Best Dr. Frankenstein voice,

“It’s Alive!”


There were so many lessons I had to learn to get this this point. Here are a short list:

  1. How to implement a Linux Kernel network device driver
  2. How to register with the Linux Kernel to get an Advanced Configuration and Power Interface (ACPI) based device from data in the Differentiated System Description Table (DSDT).
  3. How to convert physical memory offsets to virtual
  4. How to read and write data from device memory
  5. How to lookup data in the ACPI tables (a work around for a mechanism not yet written)
  6. How to work with our firmware team to get their view of the debug data
  7. How to build a firmware image and deploy it to one of our lab machines
  8. How to build and run a unit test against mock objects inside the Linux Kernel
  9. How to read and implement the MCTP and related level protocol specs.

I work with really smart people. I would probably have been able to do this all myself…in another 15 years. The amount of time saved by working with the members of my team is probably longer than the life of the product I am working on.

Someone once said, “If you are the smartest person in the room, you are probably in the wrong room.” I suspect that I am absolutely in the right room for me.

The code is by no means done. In some ways, you might say that the real work begins now: getting it production ready, However I have always used the principal of “build from success” when working in software. First get something working, then make incremental improvements while keeping it working. This is my first real success and it feels good.

Episode 399 – Curl, Security, and Daniel Stenberg

Posted by Josh Bressers on October 30, 2023 12:00 AM

Josh and Kurt talk to Daniel Stenberg about curl. Daniel is the creator of curl, we chat with him about the security of curl. Daniel tells us how curl is kept secure, we learn about some of the historical reasons curl works the way it does. We hear the story about the curl CVE situation firsthand. We also touch on the importance of curating the community of a popular open source project.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3241-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_399_Curl_Security_and_Daniel_Stenberg.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_399_Curl_Security_and_Daniel_Stenberg.mp3</audio>

Show Notes

Episode 398 – Is only 11% of open source maintained?

Posted by Josh Bressers on October 23, 2023 12:00 AM

Josh and Kurt talk about Sonatype’s 9th Annual State of the Software Supply Chain. There’s a ton of data in the report, but the thing we want to talk about is the statistic that only 11% of open source is actually being maintained. Do we think that’s true? Does it really matter?

<audio class="wp-audio-shortcode" controls="controls" id="audio-3236-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_398_Is_only_11_of_open_source_mainted.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_398_Is_only_11_of_open_source_mainted.mp3</audio>

Show Notes

No Negative Access Rules

Posted by Adam Young on October 21, 2023 10:07 PM

If you don’t want someone to be able to delete the database, do not give them authority to delete the database.

Azure recently announced that they were implementing Negative access rules. A rule of this nature is such that you/ can say “User U cannot perform action A on resource R.”

This is an anti-pattern. It is a panic response to breaches caused by principals (users or agents ) that have far more power than they should have to perform operations than they need. What is the alternative?

Create a agents with minimal access to get done exactly what they need an no more.

Lets break this on down. I am going to use a web application to explain what this should look like. This application takes orders on line and send them to a back-end processing system to fulfill. As such, there are roughly four agents for different parts of the overall system.

  • The Web server
  • The Web servers Database
  • The messaging broker
  • The back-end fulfillment system.

Ulysses is the end user. Ulysses wants to buy a thing. Ulysses opens his browser and clicks through the pages. We’ll assume that the web-server is not running as root on the remote server, as that would be bad and we’ve all grown beyond that point. It is running as, say, the STORE user. This user can render pages to send back to Ulysses, and can query the database to get categories, products, SKUs, and few more things. For write access, this user can write to the order database, and can write order messages to the message queuing system. The STORE user can also read from the order update queue to change the order management database, although this is likely done by a different agent in practice.

OK, I think you can see how this same kind of pattern would be implemented by the order fulfillment system. Lets go back to our cloud provider and discuss a little further.

Odette is our owner. She is the one that pays the Cloud provider to set up her store, to sell things. Odette has contracted to Carlita to modify her web application to customize it for her needs. Dabney is her database administrator. In addition, she uses a service from her cloud provider to set up the application in the first place.

Which of these user should have authority to delete the database? None, obviously. But how does the database get created in the first place? Automated processes set up by the cloud provider. Modifications performed on the database should happen via git, with code review required by at least one other person to accept a merge request. This merge request then goes into a staging branch, staged, and again requires manual approval to be pushed to the live server.

THE actual pushing of changes from one stage to another are performed by agents with only the ability to perform the operations they need. Create and drop tables are handled by the database management agent. And yes, this one, if compromised, could destroy the database. However, another agent performs backups prior to any operations that alter the tables. A deleted table can be created by rolling aback to a previous version, acknowledging that all data that came in post corruption will be lost.

It ain’t easy. It ain’t simple, and it ain’t free. But it is all necessary.

So why are negative rules such a big deal? Surely adding an explicit deny rule on top of all the explicit allow rules provides an added layer of security? There are a few problems with this approach, First, it only actively denies actions you have actually foreseen as problematic. For instance, it would not catch that the Store user could delete the order export queue, or that the order update agent could alter the order update table to a format that was broken. You want to deny everything by default. Then, to test to see if a user can perform a specific action, you can query the role assignments to see if a user has the dangerous permission. If they do, you probably need to create a new, more fine grained role, that has only the permissions required.

A good example of a system that works this way is SELinux. IN an SELinux hardened system, everything is forbidden until explicitly allowed. The critical tool that makes SELinux workable is permissive mode. When you run a NON_PRODUCTION system in permissive mode, you see what would have been denied by the existing set of rules, and you make new rules that would allow those actions. Then you go back into enforcing mode and run, and make sure you can get through the required workflow with all required actions allowed and all forbidden actions denied. This workflow would replace the explicit Deny rules above.

Deny rules add an additional complication. Now you need to explicitly order your rules. First, you have the default Rule of Deny All. Then you have the explicit allow rules, and finally the deny rules. But what happens if someone comes by later and wants an exception to the deny rule. Maybe this account should not be able to delete production databases, but staging ones are just fine? If your blanket deny stops them from deleting all databases, you might be stuck.

And that is what the Deny rules should be: unit tests that show an action is denied. Not an actual rule itself. Because all actions should be denied by default, and if you can accidentally assign one action, you probably accidentally allowed a bunch of other actions as well. So, do not make Deny actions part of your enforcement rule set. Make them part of your explicit tests after the fact.

Deny rules have been a part of many access control systems over the years. This is not the first time this discussion has come up, nor will it be the last. This is one of those “must have” features that keep popping up. Its an anti pattern and should be avoided. The rational developer can only say no so many times before someone does an end run around them and someone puts negative rules in the system.

Attestation in a Nutshell

Posted by Adam Young on October 21, 2023 02:32 PM

One of my current engineering efforts is in support of the concept of hardware attestation. What is that? Here’s my attempt at a summary:

Attestation is a way of showing something is true. In this case, it is proving that the software you are talking to is from a trusted vendor. In my case, that software is the Firmware for the System-on-A-Chip. While there are many levels of Attestation, they all resolve down to the lowest level software. It doesn’t matter if the Operating System is good if the Firmware is bad, there is the potential for a violation. This is no guarantee that there is not a violation. Attestation is necessary-but-not-sufficient.

How do we attest? Well, we have to talk to a server. There are two different types of servers I have been exposed to in my current effort: BMC and Operating System. They do roughly the same thing. Some external program makes a connection to either the BMC or the OS, and and makes an attestation request. “Show me the firmware you are running and a cryptographic signature for it.” Basically, I am back in the world of X509 certificates. Although attestation does not need to be done with X509, it needs all the stuff from X509 and so it is easiest to explain in terms of X509.

The building blocks:

The main building block of most computer security is the concept of asymmetric cryptography. This means that you have a computer algorithm that can encry0pt and decrypt messages. The keys used by this algorithm are related to each other but different from each other. One is going to be labeled the public key. The other is the private key. Which is which is arbitrary, but once you decide, you need to treat them consistently. If you use the public key to encrypt a message, you can only use the private key to decrypt it, But if you use the private key to encrypt a message, you can only use the public key to decrypt it. There are many ways that these are used, but I am going to focus on one of the; signatures. However, before we can explain signatures, we need one more concept: hashes.

A cryptographic hash algorithms takes a long document and produces a short string that represents that document. What is special about cryptographic hashes is that a very small change in the docuemtn produces a different hash. If you change a period to a comma, you get a different hash.

I can take the text above, starting with the phrase “Attestation is a way…” up to the phrase ” you get a Different Hash” and put and put it in a text document. I will also add an addtional line and put a period on it. I can use the program sha256sum to product the hash like this:

sha256sum attest.txt 
396f4edd98ddf09d44a2842e9495db25b7e7b5a0b5a747a4fd29b8e36c5abfab  attest.txt

However, if I change the final character from a period to a comma,

diff attest.txt attest2.txt 
10c10
< .
---
> ,

I get this:

sha256sum attest2.txt
9282e247e2b21a49731b2a631ed2fc2afb3184fc5908ee893111ad6cfb142f9e attest2.txt

A cryptographic signature for a document takes a sha256 hash and encrypts it with a private key. Now If someone wants to confirm a document, they 1. Use the public key to decrypt the hash and 2, hash the document themselves to see that the hashes match.

Attestation is based on requesting a signature for the firmware running on a system. The public key used to validate that signature comes from a cryptographic certificate (that is where X509 comes in) so you can establish a chain of trust. X509 is a fairly huge area, but the only part of it necessary to understand here is that one public key can be used to sign a document containing another public key…and so on in chains. This is how your computer set up an https session to read this blog, and also used in many of the algorithms used to identify yourself on the internet.

OK, that is a pretty big nutshell. Maybe a coconut. But I think that is a succinct as I can make it. This skips a lot of the context.

Hello To Stephen Smoogen

Posted by Adam Young on October 16, 2023 10:53 PM

This post is a novelty post merely to say hello to a friend of mine that gave me a shout out else-where.

Hi Stephen.

Building a Fedora Based Linux Kernel

Posted by Adam Young on October 16, 2023 08:06 PM

We have a few different ways we build a Kernel for internal consumption. One is very minimal, to be used when space is at a premium. Another is very closely based on the Fedora configuration to be used as a replacement Kernel for a Fedora install. While we do provide our team with RPMs to install, development often requires building from source. I’ve done this (and forgotten steps) enough times to want to have a quick reference. The following should work on a recent Fedora install.

yum groupinstall "Development Tools"
yum install dwarves openssl grubby
git clone git@$(GITSERVER):$(LINUX_REPO).git
cd linux
cp $( KERNEL_CONFIG_SOURCE) ./.config
make olddefconfig
make -j `nproc`  && make -j `nproc` modules && make -j `nproc` modules_install && make install
grubby --set-default-index=0
reboot

Episode 397 – The curl and glibc vulnerabilities

Posted by Josh Bressers on October 16, 2023 12:00 AM

Josh and Kurt talk about a curl and glibc bug. The bugs themselves aren’t super interesting, but there are other conversations around the bugs that are interesting. Why don’t we just rewrite everything in Rust? Why can’t we just train developers to stop writing insecure code. How can AI solve this problem? It’s a marvelous conversation that ends on the very basic idea: we already have the security the market demands. Unless we change that demand, security won’t change.

<audio class="wp-audio-shortcode" controls="controls" id="audio-3232-10" preload="none" style="width: 100%;"><source src="https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_397_The_curl_and_glibc_vulnerabilities.mp3?_=10" type="audio/mpeg">https://traffic.libsyn.com/opensourcesecuritypodcast/Episode_397_The_curl_and_glibc_vulnerabilities.mp3</audio>

Show Notes