Compare commits

..

10 Commits

77 changed files with 647 additions and 1478 deletions

View File

@ -1,33 +0,0 @@
name: build and deploy jekyll
on:
push:
branches:
- master
jobs:
build_and_deploy:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- name: rubygems cache
uses: actions/cache@v3
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
- name: jekyll deploy
uses: "jeffreytse/jekyll-deploy-action@v0.4.0"
with:
provider: "github"
token: ${{ secrets.GITHUB_TOKEN }}
branch: "gh-pages"
jekyll_src: "./"
jekyll_cfg: "_config.yml"
cname: "jackbondpreston.me"
actor: "jackbondpreston"
pre_build_commands: "pacman -S --noconfirm libvips lcms2 openjpeg2 libpng libwebp libheif imagemagick openslide libjxl poppler-glib"

View File

@ -1,38 +0,0 @@
# This is a basic workflow to help you get started with Actions
name: cv-build
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "master" branch
push:
branches: [ "master" ]
paths: cv/**
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
runs-on: ubuntu-latest
steps:
- name: Set up Git repository
uses: actions/checkout@v2
- name: Compile LaTeX document
uses: xu-cheng/latex-action@v2
with:
working_directory: cv
root_file: main.tex
- name: Move built .pdf
run: |
mv cv/main.pdf ./cv.pdf
- name: Commit built .pdf
uses: EndBug/add-and-commit@v9
with:
add: 'cv.pdf'
author_name: 'Jack Bond-Preston'
author_email: 'jackbondpreston@outlook.com'
message: '[github action] update cv.pdf'

4
.gitignore vendored
View File

@ -1,2 +1,2 @@
.jekyll-cache public/
_site/ static/processed_images/

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "syntaxes/console"]
path = syntaxes/console
url = https://github.com/haraldh/Sublime-console.git

1
CNAME
View File

@ -1 +0,0 @@
jackbondpreston.me

View File

@ -1,7 +0,0 @@
source "https://rubygems.org"
gem 'jekyll', '~> 4.0'
group :jekyll_plugins do
gem 'jekyll_picture_tag', '~> 2.0'
end

View File

@ -1,84 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.8.1)
public_suffix (>= 2.0.2, < 6.0)
colorator (1.1.0)
concurrent-ruby (1.1.10)
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0)
eventmachine (1.2.7)
ffi (1.15.5)
forwardable-extended (2.6.0)
http_parser.rb (0.8.0)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
jekyll (4.3.1)
addressable (~> 2.4)
colorator (~> 1.0)
em-websocket (~> 0.5)
i18n (~> 1.0)
jekyll-sass-converter (>= 2.0, < 4.0)
jekyll-watch (~> 2.0)
kramdown (~> 2.3, >= 2.3.1)
kramdown-parser-gfm (~> 1.0)
liquid (~> 4.0)
mercenary (>= 0.3.6, < 0.5)
pathutil (~> 0.9)
rouge (>= 3.0, < 5.0)
safe_yaml (~> 1.0)
terminal-table (>= 1.8, < 4.0)
webrick (~> 1.7)
jekyll-sass-converter (2.2.0)
sassc (> 2.0.1, < 3.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
jekyll_picture_tag (2.0.4)
addressable (~> 2.6)
jekyll (~> 4.0)
mime-types (~> 3.0)
objective_elements (~> 1.1)
rainbow (~> 3.0)
ruby-vips (~> 2.0.17)
kramdown (2.4.0)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.3)
listen (3.7.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.4.0)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2022.0105)
objective_elements (1.1.2)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (5.0.0)
rainbow (3.1.1)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
rexml (3.2.5)
rouge (4.0.0)
ruby-vips (2.0.17)
ffi (~> 1.9)
safe_yaml (1.0.5)
sassc (2.4.0)
ffi (~> 1.9)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
unicode-display_width (2.3.0)
webrick (1.7.0)
PLATFORMS
x86_64-linux
DEPENDENCIES
jekyll (~> 4.0)
jekyll_picture_tag (~> 2.0)
BUNDLED WITH
2.3.26

View File

@ -1 +0,0 @@
# website

View File

@ -1,10 +0,0 @@
url: "https://jackbondpreston.me" # the base hostname & protocol for your site, e.g. http://example.com
baseurl: "" # the subpath of your site, e.g. /blog
title: "jack bond-preston" # the name of your site, e.g. ACME Corp.
show_dir_listing: true
safe: false
picture:
source: "pictures/"

View File

@ -1,26 +0,0 @@
<!DOCTYPE html>
<!--
  l、
゙(゚、 。
 l、゙ ~ヽ
 じしf_, )
-->
<html lang="{{ site.lang | default: " en-US" }}">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<title>{{ page.title }} - {{ site.title }}</title>
<link rel="stylesheet" href="{{ '/assets/css/main.css' | relative_url }}">
<link rel="stylesheet" href="{{ '/assets/css/pygments.css' | relative_url }}">
</head>
<body>
{{ content }}
</body>
</html>

View File

@ -1,212 +0,0 @@
<!DOCTYPE html>
<!--
  l、
゙(゚、 。
 l、゙ ~ヽ
 じしf_, )
-->
<html lang="{{ site.lang | default: " en-US" }}">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<title>{{ page.title }} - {{ site.title }}</title>
<link rel="stylesheet" href="{{ '/assets/css/main.css' | relative_url }}">
<style>
body {
padding: 0;
margin: 0;
min-height: 100vh;
}
.wrapper {
display: grid;
grid-template-columns: 30rem auto;
grid-template-rows: auto;
gap: 0;
min-height: 100vh;
}
.article {
padding: 5rem;
padding-bottom: 1rem;
}
.side {
background-image: url(/assets/images/sensor-watch/f91w-strap.svg);
background-repeat: repeat-y;
}
.side>svg {
width: 30rem;
position: fixed;
}
@media only screen and (max-width: 1500px) {
.wrapper {
grid-template-columns: 10rem auto;
grid-template-rows: auto;
}
.side>svg {
width: 10rem;
}
.article {
padding-left: 3rem;
padding-right: 1rem;
padding-top: 1rem;
}
}
@media only screen and (max-width: 800px) {
.side {
display: none;
}
.wrapper {
grid-template-columns: auto;
grid-template-rows: auto;
}
.article {
padding: 1rem;
}
}
</style>
</head>
<body>
<div class="wrapper">
<div class="side">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 500">
<defs>
<style>
.cls-1 {
fill: #0c1113;
}
.cls-2 {
fill: none;
stroke: #f6b4c1;
stroke-miterlimit: 10;
stroke-width: 2px;
}
.cls-3 {
fill: #f6b4c1;
}
</style>
</defs>
<g id="Layer_5" data-name="Layer 5">
<rect class="cls-1" width="300" height="500" />
</g>
<g id="Layer_1" data-name="Layer 1">
<path class="cls-2"
d="M150,335.07c-21-.18-53.88.56-76.78-1-1.15.37-6.4-1.85-7.11-3.33-11.43-13.68-14.6-19.62-14.67-31.33-1-13-1.27-26.4-2-49.34" />
<path class="cls-2"
d="M150,329.83c-20.3-.19-49.15.57-71.32-1-1.12.37-7.19-1.87-7.89-3.38-11.06-13.86-13.12-19.87-13.19-31.74-.92-13.2-1-20.39-1.73-43.63" />
<path class="cls-2"
d="M150,352.07S59.42,351,58.31,350.52s-20.67-32.89-21.11-34-2.89-66.45-2.89-66.45" />
<path class="cls-2"
d="M150,364.3s-93.23-1-94.34-1.42S28.31,318.3,27.86,317.19s-2.65-67.12-2.65-67.12" />
<polyline class="cls-2" points="27.68 315.07 20.48 310.24 17.14 264.91 25.21 257.91" />
<path class="cls-2"
d="M150,335.07c21-.18,53.87.56,76.78-1,1.15.37,6.39-1.85,7.11-3.33,11.43-13.68,14.6-19.62,14.67-31.33.94-13,1.26-26.4,2-49.34" />
<path class="cls-2"
d="M150,329.83c20.29-.19,49.15.57,71.32-1,1.11.37,7.19-1.87,7.88-3.38,11.06-13.86,13.13-19.87,13.2-31.74.91-13.2,1-20.39,1.73-43.63" />
<path class="cls-2"
d="M150,352.07s90.56-1.11,91.67-1.55,20.66-32.89,21.11-34,2.89-66.45,2.89-66.45" />
<path class="cls-2"
d="M150,364.3s93.22-1,94.33-1.42,27.34-44.58,27.78-45.69,2.65-67.12,2.65-67.12" />
<polyline class="cls-2" points="272.29 315.07 279.5 310.24 282.83 264.91 274.76 257.91" />
<path class="cls-2"
d="M150,165c-21,.19-53.88-.56-76.78,1-1.15-.36-6.4,1.85-7.11,3.33C54.66,183,51.49,189,51.42,200.67c-1,13-1.27,26.39-2,49.33" />
<path class="cls-2"
d="M150,170.24c-20.3.19-49.15-.56-71.32,1-1.12-.36-7.19,1.88-7.89,3.38-11.06,13.86-13.12,19.88-13.19,31.74-.92,13.21-1,20.39-1.73,43.63" />
<path class="cls-2" d="M150,148s-90.56,1.11-91.67,1.56-20.67,32.88-21.11,34S34.31,250,34.31,250" />
<path class="cls-2"
d="M150,135.78s-93.23,1-94.34,1.41-27.33,44.59-27.78,45.7S25.21,250,25.21,250" />
<polyline class="cls-2" points="27.68 185 20.48 189.83 17.14 235.17 25.21 242.17" />
<path class="cls-2"
d="M150,165c21,.19,53.87-.56,76.78,1,1.15-.36,6.39,1.85,7.11,3.33,11.43,13.69,14.6,19.62,14.67,31.34.94,13,1.26,26.39,2,49.33" />
<path class="cls-2"
d="M150,170.24c20.29.19,49.15-.56,71.32,1,1.11-.36,7.19,1.88,7.88,3.38,11.06,13.86,13.13,19.88,13.2,31.74.91,13.21,1,20.39,1.73,43.63" />
<path class="cls-2" d="M150,148s90.56,1.11,91.67,1.56,20.66,32.88,21.11,34S265.67,250,265.67,250" />
<path class="cls-2"
d="M150,135.78s93.22,1,94.33,1.41,27.34,44.59,27.78,45.7S274.76,250,274.76,250" />
<polyline class="cls-2" points="272.29 185 279.5 189.83 282.83 235.17 274.76 242.17" />
</g>
<g id="Layer_3" data-name="Layer 3">
<path class="cls-2"
d="M224.67,250c-.35,3.5,1,31.12-1.07,33.66-1.35,4.06-5.75,5.94-9.78,5.9H86.51c-4,0-8.43-1.84-9.77-5.9-2-2.3-.74-30.41-1.07-33.66.35-3.58-.92-20.74,1.07-23.77,1.34-4.06,5.75-5.95,9.77-5.9H213.82c4,0,8.43,1.84,9.78,5.9C225.57,229.27,224.35,246.4,224.67,250Z"
id="screen" />
<path class="cls-2"
d="M229.33,247.11c-.36,4.09,1,36.37-1.13,39.33-1.43,4.75-6.09,6.95-10.35,6.89H83c-4.26.06-8.92-2.14-10.35-6.89-2.13-2.69-.78-35.53-1.13-39.33.37-4.19-1-24.23,1.13-27.77,1.43-4.75,6.09-7,10.35-6.89H217.85c4.26-.06,8.92,2.14,10.35,6.89C230.28,222.89,229,242.91,229.33,247.11Z" />
<g id="CASIO">
<path class="cls-2"
d="M97.31,181.28a3.36,3.36,0,0,0-.2-1.34,1.91,1.91,0,0,0-.44-.63,3.49,3.49,0,0,0-1.28-.31c-.36-.06-1.72-.14-2.14-.14a20.79,20.79,0,0,0-3.11.17c-.14.14-.72.28-.89.5a2.43,2.43,0,0,0-.47,1.16v1.78c0,.47-.06,1.84,0,2a2.64,2.64,0,0,0,.53,1.06,3,3,0,0,0,1.22.44,23.26,23.26,0,0,0,2.8.09,23.2,23.2,0,0,0,2.42,0,1.9,1.9,0,0,0,1.06-.41,1.32,1.32,0,0,0,.5-1.05,4.25,4.25,0,0,1,0-.78" />
<path class="cls-2"
d="M100,186.71c0-1.13,3.1-5.88,3.69-7.25a1.45,1.45,0,0,1,.23-.47c.17-.16.35-.14.93-.13s.64,0,.73.16c.75,1.48,2.61,5.22,3,5.9a4.31,4.31,0,0,1,.79,1.79" />
<line class="cls-2" x1="101.07" y1="184.13" x2="108.15" y2="184.13" />
<path class="cls-2"
d="M120,180.36c.15-2.21-2.17-1.64-4.08-1.67-1,0-2.47,0-2.75.36-1.37,1-1.23,3.06.74,3.41,1.57.31,4.21-.33,5.5.07,1.56.79,1.58,3.44-.5,3.55-1.56-.08-6.23.93-6.63-1.5" />
<path class="cls-2" d="M123.92,177.83s.14,6.61,0,9.13" />
<path class="cls-2"
d="M128.06,182.59a6.3,6.3,0,0,0,.11,2.08c.25.5.86,1.35,1.52,1.4s3.31,0,3.31,0a25.08,25.08,0,0,0,2.61,0c.28-.1.92-.1,1.06-.68s.3-.66.27-1.26-.08-2.19-.08-2.19a13.37,13.37,0,0,0,0-1.92,1.37,1.37,0,0,0-.59-.92,14.78,14.78,0,0,0-1.53-.39H132a12.52,12.52,0,0,0-2.3,0c-.28.14-.95.19-1.17.5a2.33,2.33,0,0,0-.41,1.19C128.11,180.79,128.06,182.59,128.06,182.59Z" />
</g>
<g id="F-91W">
<path class="cls-2"
d="M167.94,186.22a18.32,18.32,0,0,1,.64-2.94s.56-2.79.64-2.95a45.6,45.6,0,0,1,5.34,0" />
<path class="cls-2" d="M173.06,183.28c-.92-.11-4.48,0-4.48,0" />
<path class="cls-2" d="M176.69,183.85c2,.15,3-.31,5.25,0" />
<path class="cls-2"
d="M186.39,184.94c.84,1.58,3.78.91,4.83,0,1.69-2.54,1.8-4.89-2-4.55-6.28,1.92,2.2,5.1,3.06,1.13" />
<path class="cls-2"
d="M197.39,186.83c.09-1.6.57-2.3.92-4.25a13.46,13.46,0,0,0,.63-2.83c.09,2.21-2,2-3.58,1.92" />
<path class="cls-2"
d="M204.08,179.75s0,3.52.06,4,.12,1.9.12,1.9h1.16s1.52-2.69,1.86-3.44a4.41,4.41,0,0,1,.52-1l.32-.59,1.25,0s0,.21,0,.93-.09,3.95-.09,3.95h1.35l.41-.68c.27-.46,2.39-3.53,2.39-5.11" />
</g>
<path class="cls-2" d="M18.29,211.06H10.53s-1.46-.81-1.46,8.11c0,8.42,2.17,7.78,2.17,7.78h6.34"
onmouseover="document.getElementById('screen').style.fill='blue';"
onmouseleave="document.getElementById('screen').style.fill='none';" />
<path class="cls-2" d="M18.29,288.94H10.53s-1.46.81-1.46-8.11c0-8.42,2.17-7.78,2.17-7.78h6.34" />
<path class="cls-2" d="M281.71,288.94h7.76s1.46.81,1.46-8.11c0-8.42-2.17-7.78-2.17-7.78h-6.34" />
</g>
<g id="Layer_4" data-name="Layer 4">
<path class="cls-2"
d="M150,306.44H125.88c-1.36,0-2,.2-2.44.84-.28.44-.28.44-.56,1.94a24.24,24.24,0,0,0,0,6.59,9.45,9.45,0,0,0,2.39,4.66c1.22,1,3.81,3.56,5.47,3.61s19.25,0,19.25,0" />
<polygon class="cls-3"
points="63.43 307.26 118.99 307.26 118.99 309.26 63.91 309.26 63.43 307.26" />
<polyline class="cls-2" points="149.99 110.44 63.43 110.44 55.66 137.19" />
<polygon class="cls-3"
points="62.63 195.75 149.99 195.75 149.99 193.75 63.11 193.75 62.63 195.75" />
<line class="cls-2" x1="65.99" y1="110.44" x2="65.99" />
<line class="cls-2" x1="65.99" y1="389.42" x2="65.99" y2="500" />
<polyline class="cls-2" points="149.99 389.42 63.43 389.42 55.66 362.67" />
<path class="cls-2"
d="M150,306.44h24.11c1.36,0,2,.2,2.45.84.27.44.27.44.55,1.94a24.24,24.24,0,0,1,0,6.59,9.45,9.45,0,0,1-2.39,4.66c-1.22,1-3.8,3.56-5.47,3.61s-19.25,0-19.25,0" />
<polygon class="cls-3" points="236.56 307.26 181 307.26 181 309.26 236.08 309.26 236.56 307.26" />
<polyline class="cls-2" points="150 110.44 236.56 110.44 244.33 137.19" />
<polygon class="cls-3" points="237.36 195.75 150 195.75 150 193.75 236.89 193.75 237.36 195.75" />
<line class="cls-2" x1="234" y1="110.44" x2="234" />
<line class="cls-2" x1="234" y1="389.42" x2="234" y2="500" />
<polyline class="cls-2" points="150 389.42 236.56 389.42 244.33 362.67" />
</g>
</svg>
</div>
<div class="article">
<h1><a href="{{ page.url }}">{{ page.title }}</a></h1>
{{ content }}
<hr>
<p><a href="mailto:jackbondpreston@outlook.com">email me</a> to have a conversation</p>
</div>
</div>
</body>

View File

@ -1,13 +0,0 @@
---
layout: default
---
<div class="article">
<h1><a href="{{ page.url }}">{{ page.title }}</a></h1>
{{ content }}
<hr>
<p><a href="mailto:jackbondpreston@outlook.com">email me</a> to have a conversation</p>
</div>

View File

@ -1,6 +0,0 @@
# https://stackoverflow.com/a/53893197/
class Jekyll::MarkdownHeader < Jekyll::Converters::Markdown
def convert(content)
super.gsub(/<h(2) id="(.*?)">(.*)<\/h(\d)>/, '<h\1 id="\2">\3<a href="#\2" class="header-link">[<img src="/assets/images/link.svg" />]</a></h\1>')
end
end

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,122 +0,0 @@
$background-color: rgb(12, 17, 20);
$body-color: rgb(252, 252, 252);
$heading-color: rgb(255, 182, 193);
$link-color: rgb(252, 169, 184);
$inl-code-color: rgb(165, 214, 255);
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 400;
src: local(''),
url('../fonts/source-code-pro-v22-latin-ext_latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../fonts/source-code-pro-v22-latin-ext_latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 700;
src: local(''),
url('../fonts/source-code-pro-v22-latin-ext_latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../fonts/source-code-pro-v22-latin-ext_latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
@font-face {
font-family: 'Source Code Pro';
font-style: italic;
font-weight: 400;
src: local(''),
url('../fonts/source-code-pro-v22-latin-ext_latin-italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../fonts/source-code-pro-v22-latin-ext_latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
@font-face {
font-family: 'Source Code Pro';
font-style: italic;
font-weight: 700;
src: local(''),
url('../fonts/source-code-pro-v22-latin-ext_latin-700italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../fonts/source-code-pro-v22-latin-ext_latin-700italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
body {
background-color: $background-color;
color: $body-color;
padding-left: 5vw;
padding-right: 5vw;
padding-top: 5vh;
font-family: 'Source Code Pro';
font-size: 1.5rem;
@media screen and (max-width: 600px) {
font-size: 1rem;
}
}
h1 {
color: $heading-color;
margin: 0;
}
h2 {
margin: 0;
margin-top: 3rem;
margin-bottom: 0.5rem;
}
a {
color: $link-color;
font-weight: bold;
text-decoration: none;
}
li {
line-height: 150%;
}
.article {
p, li {
a {
font-weight: normal;
text-decoration: underline;
word-wrap: break-word;
}
code {
color: #a5d6ff;
}
}
picture img, p img {
max-width: 100%;
display: block;
}
code, pre {
font-family: 'Source Code Pro';
margin: 0;
padding: 0;
}
.header-link {
display: inline-block;
}
}
table {
border-spacing: 0;
}
h2 .header-link {
display: none;
padding-left: 10px;
font-weight: normal;
font-size: 1.3rem;
img {
height: 1.25rem;
margin-bottom: -4px;
}
}

View File

@ -1,4 +0,0 @@
---
---
@import "main";

View File

@ -1,447 +0,0 @@
pre {
font-size: 1.25rem;
margin-top: 0;
vertical-align: top;
}
figure.highlight {
margin: 0;
margin-left: 1.5rem;
display: block;
overflow-x: auto;
}
@media screen and (max-width: 600px) {
pre {
font-size: 0.8rem;
}
}
td.gutter {
padding-right: 10px;
border-right: 3px solid rgb(252, 169, 184);
border-radius: 3px;
}
td.code {
padding-left: 15px;
}
body .hll {
background-color: #6e7681
}
body .c {
color: #8b949e;
font-style: italic
}
/* Comment */
body .err {
color: #f85149
}
/* Error */
body .esc {
color: #c9d1d9
}
/* Escape */
body .g {
color: #c9d1d9
}
/* Generic */
body .k {
color: #ff7b72
}
/* Keyword */
body .l {
color: #a5d6ff
}
/* Literal */
body .n {
color: #c9d1d9
}
/* Name */
body .o {
color: #ff7b72;
font-weight: bold
}
/* Operator */
body .x {
color: #c9d1d9
}
/* Other */
body .p {
color: #c9d1d9
}
/* Punctuation */
body .ch {
color: #8b949e;
font-style: italic
}
/* Comment.Hashbang */
body .cm {
color: #8b949e;
font-style: italic
}
/* Comment.Multiline */
body .cp {
color: #8b949e;
font-weight: bold;
font-style: italic
}
/* Comment.Preproc */
body .cpf {
color: #8b949e;
font-style: italic
}
/* Comment.PreprocFile */
body .c1 {
color: #8b949e;
font-style: italic
}
/* Comment.Single */
body .cs {
color: #8b949e;
font-weight: bold;
font-style: italic
}
/* Comment.Special */
body .gd {
color: #ffa198;
background-color: #490202
}
/* Generic.Deleted */
body .ge {
color: #c9d1d9;
font-style: italic
}
/* Generic.Emph */
body .gr {
color: #ffa198
}
/* Generic.Error */
body .gh {
color: #79c0ff;
font-weight: bold
}
/* Generic.Heading */
body .gi {
color: #56d364;
background-color: #0f5323
}
/* Generic.Inserted */
body .go {
color: #8b949e
}
/* Generic.Output */
body .gp {
color: #8b949e
}
/* Generic.Prompt */
body .gs {
color: #c9d1d9;
font-weight: bold
}
/* Generic.Strong */
body .gu {
color: #79c0ff
}
/* Generic.Subheading */
body .gt {
color: #ff7b72
}
/* Generic.Traceback */
body .g-Underline {
color: #c9d1d9;
text-decoration: underline
}
/* Generic.Underline */
body .kc {
color: #79c0ff
}
/* Keyword.Constant */
body .kd {
color: #ff7b72
}
/* Keyword.Declaration */
body .kn {
color: #ff7b72
}
/* Keyword.Namespace */
body .kp {
color: #79c0ff
}
/* Keyword.Pseudo */
body .kr {
color: #ff7b72
}
/* Keyword.Reserved */
body .kt {
color: #ff7b72
}
/* Keyword.Type */
body .ld {
color: #79c0ff
}
/* Literal.Date */
body .m {
color: #a5d6ff
}
/* Literal.Number */
body .s {
color: #a5d6ff
}
/* Literal.String */
body .na {
color: #c9d1d9
}
/* Name.Attribute */
body .nb {
color: #c9d1d9
}
/* Name.Builtin */
body .nc {
color: #f0883e;
font-weight: bold
}
/* Name.Class */
body .no {
color: #79c0ff;
font-weight: bold
}
/* Name.Constant */
body .nd {
color: #d2a8ff;
font-weight: bold
}
/* Name.Decorator */
body .ni {
color: #ffa657
}
/* Name.Entity */
body .ne {
color: #f0883e;
font-weight: bold
}
/* Name.Exception */
body .nf {
color: #d2a8ff;
font-weight: bold
}
/* Name.Function */
body .nl {
color: #79c0ff;
font-weight: bold
}
/* Name.Label */
body .nn {
color: #ff7b72
}
/* Name.Namespace */
body .nx {
color: #c9d1d9
}
/* Name.Other */
body .py {
color: #79c0ff
}
/* Name.Property */
body .nt {
color: #7ee787
}
/* Name.Tag */
body .nv {
color: #79c0ff
}
/* Name.Variable */
body .ow {
color: #ff7b72;
font-weight: bold
}
/* Operator.Word */
body .pm {
color: #c9d1d9
}
/* Punctuation.Marker */
body .w {
color: #6e7681
}
/* Text.Whitespace */
body .mb {
color: #a5d6ff
}
/* Literal.Number.Bin */
body .mf {
color: #a5d6ff
}
/* Literal.Number.Float */
body .mh {
color: #a5d6ff
}
/* Literal.Number.Hex */
body .mi {
color: #a5d6ff
}
/* Literal.Number.Integer */
body .mo {
color: #a5d6ff
}
/* Literal.Number.Oct */
body .sa {
color: #79c0ff
}
/* Literal.String.Affix */
body .sb {
color: #a5d6ff
}
/* Literal.String.Backtick */
body .sc {
color: #a5d6ff
}
/* Literal.String.Char */
body .dl {
color: #79c0ff
}
/* Literal.String.Delimiter */
body .sd {
color: #a5d6ff
}
/* Literal.String.Doc */
body .s2 {
color: #a5d6ff
}
/* Literal.String.Double */
body .se {
color: #79c0ff
}
/* Literal.String.Escape */
body .sh {
color: #79c0ff
}
/* Literal.String.Heredoc */
body .si {
color: #a5d6ff
}
/* Literal.String.Interpol */
body .sx {
color: #a5d6ff
}
/* Literal.String.Other */
body .sr {
color: #79c0ff
}
/* Literal.String.Regex */
body .s1 {
color: #a5d6ff
}
/* Literal.String.Single */
body .ss {
color: #a5d6ff
}
/* Literal.String.Symbol */
body .bp {
color: #c9d1d9
}
/* Name.Builtin.Pseudo */
body .fm {
color: #d2a8ff;
font-weight: bold
}
/* Name.Function.Magic */
body .vc {
color: #79c0ff
}
/* Name.Variable.Class */
body .vg {
color: #79c0ff
}
/* Name.Variable.Global */
body .vi {
color: #79c0ff
}
/* Name.Variable.Instance */
body .vm {
color: #79c0ff
}
/* Name.Variable.Magic */
body .il {
color: #a5d6ff
}
/* Literal.Number.Integer.Long */

View File

@ -1,5 +1,5 @@
CFLAGS += -Wall -g -fno-stack-protector CFLAGS += -Wall -g -fno-stack-protector -O0
CC ?= clang CC := clang
PURECAP_CC ?= ~/cheri/output/sdk/utils/cheribsd-riscv64-purecap-clang PURECAP_CC ?= ~/cheri/output/sdk/utils/cheribsd-riscv64-purecap-clang
SOURCES := $(wildcard *.c) SOURCES := $(wildcard *.c)

BIN
code/cheri/membug Executable file

Binary file not shown.

BIN
code/cheri/ptrs_as_numbers Executable file

Binary file not shown.

View File

@ -2,20 +2,21 @@
int main() { int main() {
int magic = 9999; int magic = 9999;
(void)magic; (void)magic; // suppress unused warning
int arr[] = { 1234, 5678 }; int arr[] = { 1234, 5678 };
int *x = &(arr[0]); // x is a pointer to first element of arr int *x = &(arr[0]); // x is a pointer to first element of arr
printf("*x=%d\n", *x); printf("*(%lx)=%d\n", (size_t) x, *x);
unsigned long x_addr = (size_t) x; // we're going to assume size_t = unsigned long here unsigned long x_addr = (size_t) x; // we're going to assume size_t = unsigned long here
x_addr += 4; // sizeof(int) == 4 x_addr += 4; // sizeof(int) == 4
x = (int *) x_addr; x = (int *) x_addr;
printf("*x=%d\n", *x); printf("*(%lx)=%d\n", (size_t) x, *x);
x_addr += 4; x_addr += 4;
x = (int *) x_addr; x = (int *) x_addr;
printf("*x=%d\n", *x); printf("*(%lx)=%d\n", (size_t) x, *x);
return 0; return 0;
} }

BIN
code/cheri/ptrtypes Executable file

Binary file not shown.

BIN
code/cheri/ptrtypes-cheribsd Executable file

Binary file not shown.

37
code/cheri/ptrtypes.c Normal file
View File

@ -0,0 +1,37 @@
#include <stdio.h>
#include <stdint.h>
int main() {
printf("type size (hex) size (dec)\n");
printf("=====================================\n");
#ifdef __PTRADDR_TYPE__
printf("ptraddr_t 0x%.2lx %.2lu\n", sizeof(ptraddr_t), sizeof(ptraddr_t));
#endif
printf("uintptr_t 0x%.2lx %.2lu\n", sizeof(uintptr_t), sizeof(uintptr_t));
printf("size_t 0x%.2lx %.2lu\n", sizeof(size_t), sizeof(size_t));
printf("void* 0x%.2lx %.2lu\n", sizeof(void*), sizeof(void*));
printf("=====================================\n");
#ifdef __CHERI__
int x = 111;
int y[] = { 888, 999 };
int *a = &x;
int *b = &(y[0]);
// transplant address from capability a to capability b
printf("*b: %d\n", *b);
ptraddr_t a_addr = __builtin_cheri_address_get(a);
b = __builtin_cheri_address_set(a, a_addr);
printf("*b: %d\n", *b);
b = &(y[0]);
// uintptr_t is an unsigned integer type that preserves capabilities
uintptr_t b_uintptr = (uintptr_t) b;
b_uintptr += sizeof(int);
b = (int*) b_uintptr;
printf("*b: %d\n", *b);
#endif
return 0;
}

BIN
code/cheri/sizes Executable file

Binary file not shown.

14
config.toml Normal file
View File

@ -0,0 +1,14 @@
base_url = "https://jackbondpreston.me"
compile_sass = true
build_search_index = false
generate_feed = true
[markdown]
highlight_code = true
extra_syntaxes_and_themes = ["syntaxes/console/Sublime-console/"]
[slugify]
anchors = "on"
[extra]

View File

@ -1,7 +1,10 @@
--- +++
layout: default title = "home"
title: jack bond-preston sort_by = "date"
--- template = "index.html"
page_template = "article.html"
insert_anchor_links = "right"
+++
# jack bond-preston # jack bond-preston
@ -15,18 +18,10 @@ my cv is available for viewing [here](cv.pdf).
i have personal accounts on [github](https://github.com/jackbondpreston) and [gitlab](https://gitlab.com/jackbondpreston) i have personal accounts on [github](https://github.com/jackbondpreston) and [gitlab](https://gitlab.com/jackbondpreston)
some of my work at arm on [morello](https://www.arm.com/architecture/cpu/morello) is available on the some of my work at arm on [morello](https://www.arm.com/architecture/cpu/morello) is available on the [morello musl gitlab](https://git.morello-project.org/morello/musl-libc/-/commits/morello/master?author=Jack%20Bond-Preston)
d [morello musl gitlab](https://git.morello-project.org/morello/musl-libc/-/commits/morello/master?author=Jack%20Bond-Preston)
my [onload](https://www.xilinx.com/products/boards-and-kits/x2-series/onload.html) commits at amd can be found on [the github repo](https://github.com/Xilinx-CNS/onload/commits?author=jbondpre-amd) my [onload](https://www.xilinx.com/products/boards-and-kits/x2-series/onload.html) commits at amd can be found on [the github repo](https://github.com/Xilinx-CNS/onload/commits?author=jbondpre-amd)
## articles <h2>articles<a href="/feed.xml" class="atom-link">[atom feed]</a></h2>
{% for post in site.posts %}
<li>
[{{ post.date | date: "%d/%m/%Y" }}] <a href="{{ post.url }}">{{ post.title }}</a>
</li>
{% endfor %}

View File

@ -1,50 +1,58 @@
--- +++
layout: post title = "CHERI"
title: "CHERI" date = 2022-11-19
--- +++
## preamble ## preamble
[CHERI](https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/) is an acronym for Capability Hardware Enhanced RISC Instructions. it is a security-focussed project aimed at improving memory protection at the hardware level. the project is complex and it has many potential applications. [CHERI](https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/) is an acronym for Capability Hardware Enhanced RISC Instructions. it is a security-focussed project aimed at improving memory protection at the hardware level. the project is complex and it has many potential applications.
in this article I will go into some basics to give an understanding behind some changes that CHERI makes to how programs execute and are written. this will be focussed almost entirely in C, as this is where my experience lies - it is also where some of the effects of CHERI are most easily felt.this article is going to be a _very simplistic_ introduction to CHERI, and I'm going to attempt to explain the basics behind everything I cover. a basic understanding of C will be beneficial. in this article I will go into some basics to give an understanding behind some changes that CHERI makes to how programs execute and are written. this will be focussed almost entirely in C, as this is where my experience lies - it is also where some of the effects of CHERI are most easily felt.this article is going to be a _very simplistic_ introduction to CHERI, and I'm going to attempt to explain the basics behind everything I cover. a basic understanding of C will be necessary.
***note:*** [the Morello platform](https://www.arm.com/architecture/cpu/morello) is an evaluation board produced by [Arm](https://www.arm.com/) to provide a physical implementation of CHERI extending [the Arm AArch64 ISA](https://en.wikipedia.org/wiki/AArch64). I previously worked on this platform at Arm, [porting the musl C library to Morello](https://git.morello-project.org/morello/musl-libc/). implementations for CHERI that are worth looking into from a more open perspective <a href="https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-951.pdf"> are the MIPS (chapter 4) and RISC-V (chapter 5) ones</a>. Morello is the only implementation that exists in a true hard core format, afaik - but this is obviously hard to obtain so you'll just be playing around with emulators/models anyway. ***note:*** [the Morello platform](https://www.arm.com/architecture/cpu/morello) is an evaluation board produced by [Arm](https://www.arm.com/) to provide a physical implementation of CHERI extending [the Arm AArch64 ISA](https://en.wikipedia.org/wiki/AArch64). I previously worked on this platform at Arm, [porting the musl C library to Morello](https://git.morello-project.org/morello/musl-libc/). implementations for CHERI that are worth looking into from a more open perspective <a href="https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-951.pdf"> are the MIPS (chapter 4) and RISC-V (chapter 5) ones</a>. Morello is the only implementation that exists in a true hard core format, afaik - but this is obviously hard to obtain so you'll just be playing around with emulators/models anyway.
## memory safety bugs ## memory safety bugs
to first understand how CHERI tries to fix some simple issues, let's first look at some simplified examples of issues that arise when we aren't using a CHERI-based architecture. to understand how CHERI tries to fix some simple issues, we'll first look at some simplified examples of issues that arise when we aren't using a CHERI-based architecture.
### a simple memory safety bug ### a simple memory safety bug
let's take a look at this C code: let's take a look at this C code:
{% highlight c linenos %} {{ code(path="cheri/membug.c", syntax="c", linenos=true) }}
{% include_relative code/membug.c %}
{% endhighlight %}
now let's try using our new program: and try running the compiled output of said program:
{% highlight console %} ```console
$ ./membug $ ./membug
enter your name: jack enter your name: jack
hello jack hello jack
my_perfect_string: what a beautiful string my_perfect_string: what a beautiful string
{% endhighlight %} ```
works on my machine boss! code review +1, and merged... until our good friend <a href="https://en.wikipedia.org/wiki/Hubert_Blaine_Wolfeschlegelsteinhausenbergerdorff_Sr.">Hubert Blaine Wolfeschlegelsteinhausenbergerdorff Sr.</a> comes along. he emails me a strangeerror he's seen: works on my machine boss! code review +1, and merged...
{% highlight console %} ...until our good friend [Hubert Blaine Wolfeschlegelsteinhausenbergerdorff Sr.](https://en.wikipedia.org/wiki/Hubert_Blaine_Wolfeschlegelsteinhausenbergerdorff_Sr.) comes along. he emails me a strange error he's running into:
```console
$ ./membug $ ./membug
enter your name: Hubert Blaine Wolfeschlegelsteinhausenbergerdorff Sr. enter your name: Hubert Blaine Wolfeschlegelsteinhausenbergerdorff Sr.
hello Hubert Blaine Wolfeschlegelsteinhausenbergerdorff Sr. hello Hubert Blaine Wolfeschlegelsteinhausenbergerdorff Sr.
my_perfect_string: hausenbergerdorff Sr. my_perfect_string: hausenbergerdorff Sr.
{% endhighlight %} ```
that's not supposed to happen! his name has spilled over into our `my_perfect_string[]` array! turns out our issue is that when we use `fgets()`, we've set the second parameter, `size`, to `1000` - but our `user_name[32]` array c1593an only fit 32 characters (and the last of these should be a null terminator, so 31 usable characters). ***note:*** if you compile and run this on your machine, you may not get the same output. that's because we're invoking *undefined behaviour* here, so the compiler can kind of do whatever it wants. I'll always provide the output that demonstrates what I'm trying to show when giving examples like this. for what it's worth, I'm running `clang 10.0.0-4ubuntu1` with target `x86_64-pc-linux-gnu`. compilation options, the `Makefile`, and such are available [code subdirectory of this article's source](https://github.com/jackbondpreston/jackbondpreston.github.io/tree/master/_posts/cheri/code).
`fgets` fills up `user_name`, but it hasn't finished with the name yet! it doesn't care (or know) that `user_name` is full, it's just going to keep going until it finishes our user input, or reads 999 characters from standard input. and thus it keeps mindlessly writing, overwriting the memory we've used to store our precious perfect string (which happens to be immediately after `user_name`). let's take a look at the stack in GDB to see why this happens: that's not supposed to happen! his name has spilled over into our `my_perfect_string[]` array! turns out our issue is that when we use `fgets(char *str, int count, FILE *stream)`, we've set the second parameter (`size`) to `1000` - but our `user_name[32]` array can only fit 32 characters (and the last of these should be a null terminator, so 31 usable characters).
{% highlight plaintext %} `fgets()` fills up `user_name`, but it hasn't finished with the name yet! it doesn't care (or know) that `user_name` is full, it's just going to keep going until it finishes our user input, or reads 999 characters from standard input. thus it keeps mindlessly writing, overwriting the section memory we've used to store our precious perfect string (which happens to be immediately after `user_name`).
***note:*** `fgets()` has a cousin, `gets(char *s)`, which is particularly poor with regards to memory safety (due to lack of `size` parameter), [and has largely been moved away from in modern C](https://linux.die.net/man/3/fgets):
> LSB deprecates `gets()`. POSIX.1-2008 marks `gets()` obsolescent. ISO C11 removes the specification of `gets()` from the C language, and since version 2.16, glibc header files don't expose the function declaration if the `_ISOC11_SOURCE` feature test macro is defined.
let's take a look at the stack in GDB to see how this happens:
```gdb
(gdb) b memdebug.c:7 (gdb) b memdebug.c:7
(gdb) run (gdb) run
Breakpoint 1, main () at membug.c:7 Breakpoint 1, main () at membug.c:7
@ -61,59 +69,61 @@ Breakpoint 1, main () at membug.c:7
0x7fffffffdc10: 119 'w' 104 'h' 97 'a' 116 't' 32 ' ' 97 'a' 32 ' ' 98 'b' 0x7fffffffdc10: 119 'w' 104 'h' 97 'a' 116 't' 32 ' ' 97 'a' 32 ' ' 98 'b'
0x7fffffffdc18: 101 'e' 97 'a' 117 'u' 116 't' 105 'i' 102 'f' 117 'u' 108 'l' 0x7fffffffdc18: 101 'e' 97 'a' 117 'u' 116 't' 105 'i' 102 'f' 117 'u' 108 'l'
0x7fffffffdc20: 32 ' ' 115 's' 116 't' 114 'r' 105 'i' 110 'n' 103 'g' 0 '\000' 0x7fffffffdc20: 32 ' ' 115 's' 116 't' 114 'r' 105 'i' 110 'n' 103 'g' 0 '\000'
{% endhighlight %} ```
we can see our two character arrays are right next to each other on the stack (`user_name` contains some gibberish as it is not zero-initialised). we can see our two character arrays are right next to each other on the stack (`user_name` contains some gibberish as it is not zero-initialised).
***note:*** this code was compiled with `-fno-stack-protector` to reproduce this behaviour. compilers have certain techniques like this which can help protect against such attacks, but there are often ways around these by using less primitive attacks. ***note:*** this code was compiled with `-fno-stack-protector` to reproduce this behaviour. compilers have certain techniques which can help protect against such attacks, but there are often ways around these by using less primitive attacks. we are just ignoring these in this article for simplicity.
okay, it's a pretty easy fix, we just need to change the `fgets(char *s, int size, FILE *stream)` parameter `size` to `32`. okay, at least it's a pretty easy fix: we just need to change the `fgets()` parameter `size` to `32`.
***note:*** you may initially think "why not 31? don't we need to save a character for the null byte at the end?". thankfully, `fgets` does this for us. excerpt from `man fgets`: ***note:*** you may initially think "why not `31`? don't we need to save a character for the null byte at the end?". thankfully, `fgets` does this for us. excerpt from `man fgets`:
> "fgets() reads in _at most one less than size_ characters from stream and stores them into the buffer pointed to by s [...] A terminating null byte ('\0') is stored after the last character in the buffer". > `"fgets() reads in _at most one less than size_ characters from stream and stores them into the buffer pointed to by s [...] A terminating null byte ('\0') is stored after the last character in the buffer".`
this is a good question to be asking though, being careful is key when it comes to these kinds of things. this is a good question to be asking though, being careful is key when it comes to these kinds of things.
### why hardware? ### why hardware?
okay, so that's an easy fix. why are we talking about doing anything in hardware here? just write the code correctly! the issue is code gets very complex, and this is a very simplistic situation. some memory safety bugs can be incredibly complicated and go unnoticed for decades. the C language especially gives the programmer many, many opportunities to make mistakes - and it only takes one to be a problem. a lot of the software we are using these days is based on stacks upon stacks of software written in different languages, and there are going to be bugs in there. CHERI should give us some protection "for free" (it's not this simple, in actuality). okay, that wasn't too bad. why are we talking about doing anything in hardware here? just write the code correctly!
some languages (e.g. Rust) are going to offer you strong memory safety guarantees at compile-time, but that's not the topic of this article. the differences between doing this kind of protection in software or hardware (or both) is more complex than the scope of this article. in addition, CHERI's benefits are more wide in breadth than just protecting against this kind of issue. we've looked at a very simplistic situation, with no real stakes and nothing to exploit (and an unrealistically simple bug). if this bug was exploitable for malicious gain, it could already be too late by the time we found it.
memory safety problems make up the vast majority of problematic security issues. the Chromium project [found 70% of its serious security bugs were memory safety related](https://www.chromium.org/Home/chromium-security/memory-safety/) and [Microsoft found the same prevalence](https://msrc-blog.microsoft.com/2019/07/16/a-proactive-approach-to-more-secure-code/). some memory safety bugs can be incredibly complicated and go unnoticed for decades. the C language especially gives the programmer many, many opportunities to make mistakes - and it only takes one to be a problem. a lot of the software we are using these days is based on layers upon layers of software written in different languages, and there are going to be bugs in there. CHERI aims to give us some protection at a hardware level.
***Note:*** some languages (e.g. Rust) are going to offer you strong memory safety guarantees at compile-time, but I'm not going to include the discussions around this and how it compares to CHERI in this article. this article will focussed on how CHERI applies to C (and to some extent, C++ by extension).
## pointers recap ## pointers recap
let's quickly recap a basic idea of what a pointer is. we're going to ignore things like [virtual memory](https://en.wikipedia.org/wiki/Virtual_memory) for brevity. we can think of a pointer in a normal 64-bit architecture (e.g. AArch64) simply as a 64-bit unsigned value that holds the memory address of something we care about. this is a simplification (as are most things), but it can help us reason about the general idea: let's quickly recap a basic idea of what a pointer is. we're going to ignore things like [virtual memory](https://en.wikipedia.org/wiki/Virtual_memory) for brevity. we can think of a pointer in a normal 64-bit architecture (e.g. AArch64) simply as a 64-bit unsigned value that holds the memory address of something we care about. this is a simplification (as are most things), but it can help us reason about the general idea:
{% highlight c %} ```c
int val = 1593; int val = 1593;
int *x = &val; // x points to val int *x = &val; // x points to val
{% endhighlight %} ```
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 314"><defs><style>.prefix__prefix__d{fill:none;stroke-miterlimit:10}.prefix__prefix__f,.prefix__prefix__h,.prefix__prefix__i{font-size:24px}.prefix__prefix__f,.prefix__prefix__h,.prefix__prefix__k{fill:#fcfcfc}.prefix__prefix__f,.prefix__prefix__l{font-family:Source Code Pro}.prefix__prefix__d{stroke:gray;stroke-width:4px}.prefix__prefix__h,.prefix__prefix__m{font-family:Source Code Pro;font-weight:700}.prefix__prefix__i{fill:gray}</style></defs><g id="prefix__prefix__a"><path fill="#0c1114" d="M0 0h1920v314H0z"/><text class="prefix__prefix__h" transform="translate(577.46 133.41)"><tspan x="0" y="0">int *x</tspan></text><text class="prefix__prefix__f" transform="translate(490.97 177.1)"><tspan x="0" y="0">0x0000010000000004</tspan></text><path d="M481.16 206v18.5M760.5 206v18.5m-279 0h279" stroke="#fcfcfc" fill="none" stroke-miterlimit="10" stroke-linecap="square" stroke-width="3"/><text transform="translate(578.78 241.33)" font-size="20" font-family="Source Code Pro" fill="#fcfcfc"><tspan x="0" y="0">address</tspan></text><path stroke-width="4" stroke="#fcfcfc" fill="none" stroke-miterlimit="10" d="M752 171h204.56"/><path class="prefix__prefix__k" d="M948.64 182.62L992 171.01l-43.36-11.63v23.24z"/><text transform="translate(1272.76 177.16)" fill="#fcfcfc" font-size="24"><tspan class="prefix__prefix__m" x="0" y="0">mem[</tspan><tspan class="prefix__prefix__l" x="57.6" y="0">0x0000010000000004</tspan><tspan class="prefix__prefix__m" x="316.79" y="0">]</tspan></text><text class="prefix__prefix__i" transform="translate(1272.76 133.16)"><tspan class="prefix__prefix__m" x="0" y="0">mem[</tspan><tspan class="prefix__prefix__l" x="57.6" y="0">0x0000010000000000</tspan><tspan class="prefix__prefix__m" x="316.79" y="0">]</tspan></text><text class="prefix__prefix__i" transform="translate(1271.76 224.16)"><tspan class="prefix__prefix__m" x="0" y="0">mem[</tspan><tspan class="prefix__prefix__l" x="57.6" y="0">0x0000010000000008</tspan><tspan class="prefix__prefix__m" x="316.79" y="0">]</tspan></text></g><g id="prefix__prefix__b"><path class="prefix__prefix__d" d="M1260 58v48H985V58"/><path d="M1258 195v40H987v-40h271m4-4H983v48h279v-48zm-4-84v40H987v-40h271m4-4H983v48h279v-48z" fill="gray"/><path class="prefix__prefix__k" d="M756.16 150.93v40h-271v-40h271m4-4h-279v48h279v-48zM1258 151v40H987v-40h271m4-4H983v48h279v-48z"/><text class="prefix__prefix__f" transform="translate(1094 177.09)"><tspan x="0" y="0">1593</tspan></text><text class="prefix__prefix__h" transform="translate(1007.6 45.16)"><tspan x="0" y="0">memory (as ints)</tspan></text><path class="prefix__prefix__d" d="M1260 284v-48H985v48"/></g></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 314"><defs><style>.prefix__prefix__d{fill:none;stroke-miterlimit:10}.prefix__prefix__f,.prefix__prefix__h,.prefix__prefix__i{font-size:24px}.prefix__prefix__f,.prefix__prefix__h,.prefix__prefix__k{fill:#fcfcfc}.prefix__prefix__f,.prefix__prefix__l{font-family:Source Code Pro}.prefix__prefix__d{stroke:gray;stroke-width:4px}.prefix__prefix__h,.prefix__prefix__m{font-family:Source Code Pro;font-weight:700}.prefix__prefix__i{fill:gray}</style></defs><g id="prefix__prefix__a"><path fill="#0c1114" d="M0 0h1920v314H0z"/><text class="prefix__prefix__h" transform="translate(577.46 133.41)"><tspan x="0" y="0">int *x</tspan></text><text class="prefix__prefix__f" transform="translate(490.97 177.1)"><tspan x="0" y="0">0x0000010000000004</tspan></text><path d="M481.16 206v18.5M760.5 206v18.5m-279 0h279" stroke="#fcfcfc" fill="none" stroke-miterlimit="10" stroke-linecap="square" stroke-width="3"/><text transform="translate(578.78 241.33)" font-size="20" font-family="Source Code Pro" fill="#fcfcfc"><tspan x="0" y="0">address</tspan></text><path stroke-width="4" stroke="#fcfcfc" fill="none" stroke-miterlimit="10" d="M752 171h204.56"/><path class="prefix__prefix__k" d="M948.64 182.62L992 171.01l-43.36-11.63v23.24z"/><text transform="translate(1272.76 177.16)" fill="#fcfcfc" font-size="24"><tspan class="prefix__prefix__m" x="0" y="0">mem[</tspan><tspan class="prefix__prefix__l" x="57.6" y="0">0x0000010000000004</tspan><tspan class="prefix__prefix__m" x="316.79" y="0">]</tspan></text><text class="prefix__prefix__i" transform="translate(1272.76 133.16)"><tspan class="prefix__prefix__m" x="0" y="0">mem[</tspan><tspan class="prefix__prefix__l" x="57.6" y="0">0x0000010000000000</tspan><tspan class="prefix__prefix__m" x="316.79" y="0">]</tspan></text><text class="prefix__prefix__i" transform="translate(1271.76 224.16)"><tspan class="prefix__prefix__m" x="0" y="0">mem[</tspan><tspan class="prefix__prefix__l" x="57.6" y="0">0x0000010000000008</tspan><tspan class="prefix__prefix__m" x="316.79" y="0">]</tspan></text></g><g id="prefix__prefix__b"><path class="prefix__prefix__d" d="M1260 58v48H985V58"/><path d="M1258 195v40H987v-40h271m4-4H983v48h279v-48zm-4-84v40H987v-40h271m4-4H983v48h279v-48z" fill="gray"/><path class="prefix__prefix__k" d="M756.16 150.93v40h-271v-40h271m4-4h-279v48h279v-48zM1258 151v40H987v-40h271m4-4H983v48h279v-48z"/><text class="prefix__prefix__f" transform="translate(1094 177.09)"><tspan x="0" y="0">1593</tspan></text><text class="prefix__prefix__h" transform="translate(1007.6 45.16)"><tspan x="0" y="0">memory (as ints)</tspan></text><path class="prefix__prefix__d" d="M1260 284v-48H985v48"/></g></svg>
and on these normal architectures, this pointer generally is just a number. we can do weird things with it, treating it as a number... and on these normal architectures, this pointer generally is just a number. we can do weird things with it, treating it as a number...
{% highlight c linenos %} {{ code(path="cheri/ptrs_as_numbers.c", syntax="c", linenos=true) }}
{% include_relative code/ptrs_as_numbers.c %}
{% endhighlight %}
...and this code will often still work: ...and this code will often still work:
{% highlight console %} ```console
$ ./ptrs_as_numbers $ ./ptrs_as_numbers
*x=1234 *(7fff98640c20)=1234
*x=5678 *(7fff98640c24)=5678
*x=9999 *(7fff98640c28)=9999
{% endhighlight %} ```
yikes! now, when you start messing with pointers like this, you're bound to run into a bunch of undefined behaviour. but C programmers write undefined behaviour all the time, and my computer executes this program fine without complaining at all. doesn't it feel a bit weird that we can take a pointer to `arr[0]` and modify it to load `secret`? they're not even part of the same array... yikes! now, when you start messing with pointers like this, you're bound to run into a bunch of undefined behaviour. but C programmers write undefined behaviour all the time (and not always by accident), and my computer executes this program fine without complaining at all. doesn't it feel a bit weird that we can take a pointer to `arr[0]` and modify it to load `secret`? they're not even part of the same array...
## introducting capabilities ## introducting capabilities
CHERI introduces capabilities, which can be thought of as an extension to pointers. they still store an address of something we care about, but they have extra information too! in a 64-bit system, a pointer would typically be a 64-bit value (as dicussed previously). the corresponding capability in a CHERI platform is 128 bits (or 129 bits if you look at it a certain way, more about that later...). CHERI introduces capabilities, which can be thought of as an extension to pointers. they still store an address of something we care about, but they have extra information too! in a 64-bit system, a pointer would typically be a 64-bit value (as dicussed previously). the corresponding capability in a CHERI platform is 128 bits (or 129 bits if you look at it a certain way, more about that later).
as you might have guessed, this "extra information" takes up 64 bits of the capability. bits are assigned to three key pieces of metadata: *bounds*, *permissions*, and *object type*. there is also an additional 1-bit _tag_ which is stored out-of-band: it is not a 129-bit value - instead each 128-bit capability can be thought of as being associated with a 1-bit validity tag. the architecture manages this. the diagram below is provided as a rough overview of this. note that it is not to scale. as you might have guessed, this "extra information" takes up 64 bits of the capability. bits are assigned to three key pieces of metadata: *bounds*, *permissions*, and *object type*. there is also an additional 1-bit _tag_ which is stored out-of-band: it is not a 129-bit value - instead each 128-bit capability can be thought of as being associated with a 1-bit validity tag. the architecture manages this association for us. the diagram below is provided as a rough overview of this. note that it is not to scale.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 314"><defs><style>.prefix__c{fill:none;stroke:#fcfcfc;stroke-linecap:square;stroke-miterlimit:10;stroke-width:3px}.prefix__f,.prefix__g{fill:#fcfcfc}.prefix__f{font-family:Source Code Pro;font-size:20px}</style></defs><g id="prefix__a"><path fill="#0c1114" d="M0 0h1920v314H0z"/><text transform="translate(101.86 232.41)" font-family="Source Code Pro" font-weight="700" fill="#fcfcfc" font-size="24"><tspan x="0" y="0">int *x (capability)</tspan></text><text transform="translate(1205.97 232.1)" font-family="Source Code Pro" fill="#fcfcfc" font-size="24"><tspan x="0" y="0">0x0000010000000004</tspan></text><path class="prefix__c" d="M1016 261v18.5M1656 261v18.5M1016 279.5h640"/><text class="prefix__f" transform="translate(1293.78 296.33)"><tspan x="0" y="0">address</tspan></text><path class="prefix__c" d="M700 191.5V173M1020 191.5V173M700 173h320"/><text class="prefix__f" transform="translate(823.78 167.74)"><tspan x="0" y="0">bounds</tspan></text><path class="prefix__c" d="M554 260.34v18.5M704 260.34v18.5M554 278.84h150"/><text class="prefix__f" transform="translate(562.78 295.68)"><tspan x="0" y="0">object type</tspan></text><g><path class="prefix__c" d="M391.89 191.56v-18.5M541.89 191.56v-18.5M391.89 173.06h150"/></g><text class="prefix__f" transform="translate(400.67 167.8)"><tspan x="0" y="0">permissions</tspan></text><text class="prefix__f" transform="translate(304.67 31.07)"><tspan x="0" y="0">tag (out-of-band)</tspan></text><g><path class="prefix__c" d="M391.33 55.92v-18.5M421.33 55.92v-18.5M391.33 37.42h30"/></g></g><g id="prefix__b"><path class="prefix__g" d="M1651.66 205.93v40h-632v-40h632m4-4h-640v48h640v-48z"/><path class="prefix__g" d="M1016 206v40H704v-40h312m4-4H700v48h320v-48z"/><path class="prefix__g" d="M700 206v40H558v-40h142m4-4H554v48h150v-48z"/><path class="prefix__g" d="M554 206v40h-12v-40h12m4-4h-20v48h20v-48z"/><path class="prefix__g" d="M538 206v40H396v-40h142m4-4H392v48h150v-48zM418.5 70v40h-22V70h22m4-4h-30v48h30V66z"/></g></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 314"><defs><style>.prefix__c{fill:none;stroke:#fcfcfc;stroke-linecap:square;stroke-miterlimit:10;stroke-width:3px}.prefix__f,.prefix__g{fill:#fcfcfc}.prefix__f{font-family:Source Code Pro;font-size:20px}</style></defs><g id="prefix__a"><path fill="#0c1114" d="M0 0h1920v314H0z"/><text transform="translate(101.86 232.41)" font-family="Source Code Pro" font-weight="700" fill="#fcfcfc" font-size="24"><tspan x="0" y="0">int *x (capability)</tspan></text><text transform="translate(1205.97 232.1)" font-family="Source Code Pro" fill="#fcfcfc" font-size="24"><tspan x="0" y="0">0x0000010000000004</tspan></text><path class="prefix__c" d="M1016 261v18.5M1656 261v18.5M1016 279.5h640"/><text class="prefix__f" transform="translate(1293.78 296.33)"><tspan x="0" y="0">address</tspan></text><path class="prefix__c" d="M700 191.5V173M1020 191.5V173M700 173h320"/><text class="prefix__f" transform="translate(823.78 167.74)"><tspan x="0" y="0">bounds</tspan></text><path class="prefix__c" d="M554 260.34v18.5M704 260.34v18.5M554 278.84h150"/><text class="prefix__f" transform="translate(562.78 295.68)"><tspan x="0" y="0">object type</tspan></text><g><path class="prefix__c" d="M391.89 191.56v-18.5M541.89 191.56v-18.5M391.89 173.06h150"/></g><text class="prefix__f" transform="translate(400.67 167.8)"><tspan x="0" y="0">permissions</tspan></text><text class="prefix__f" transform="translate(304.67 31.07)"><tspan x="0" y="0">tag (out-of-band)</tspan></text><g><path class="prefix__c" d="M391.33 55.92v-18.5M421.33 55.92v-18.5M391.33 37.42h30"/></g></g><g id="prefix__b"><path class="prefix__g" d="M1651.66 205.93v40h-632v-40h632m4-4h-640v48h640v-48z"/><path class="prefix__g" d="M1016 206v40H704v-40h312m4-4H700v48h320v-48z"/><path class="prefix__g" d="M700 206v40H558v-40h142m4-4H554v48h150v-48z"/><path class="prefix__g" d="M554 206v40h-12v-40h12m4-4h-20v48h20v-48z"/><path class="prefix__g" d="M538 206v40H396v-40h142m4-4H392v48h150v-48zM418.5 70v40h-22V70h22m4-4h-30v48h30V66z"/></g></svg>
@ -123,13 +133,13 @@ I am mostly going to focus on _bounds_ in this article, as it is not too difficu
can you imagine how we can use bounds to prevent our previous memory safety bug from occurring? the key is that we can set the bounds on the capability pointing to `user_name` which we pass to `fgets`, such that the capability may only access the contents of the array. this means that when `fgets` tries to write past the end of the `user_name` array, the processor will throw a *capability fault*, and execution of our program will cease. can you imagine how we can use bounds to prevent our previous memory safety bug from occurring? the key is that we can set the bounds on the capability pointing to `user_name` which we pass to `fgets`, such that the capability may only access the contents of the array. this means that when `fgets` tries to write past the end of the `user_name` array, the processor will throw a *capability fault*, and execution of our program will cease.
the idea behind CHERI is that we don't have to set up these bounds ourselves. this is something the compiler can generate code for. the compiler knows that the `user_name` array has a length of `32`, and can set the bounds accordingly on capabilities created that point to it. let's try it... the idea behind CHERI is that we as the C programmer don't have to set up these bounds ourselves most of the time---this is something the compiler can generate code for. the compiler knows that the `user_name` array has a length of `32`, and can set the bounds accordingly on capabilities created that point to it. let's try it...
## playing with CHERI RISC-V ## playing with CHERI RISC-V
unless you're lucky enough to have access to a physical Morello board, there is the issue of actually using a CHERI implementation. for this article I will be making use of the [QEMU](https://en.wikipedia.org/wiki/QEMU) emulator to emulate a [RISC-V](https://en.wikipedia.org/wiki/RISC-V) CHERI environment. running [CheriBSD](https://www.cheribsd.org/) on this emulator will allow us to have a nice [FreeBSD](https://www.freebsd.org/)-based capability-enabled environment to play around with. I'll use [cheribuild](https://github.com/CTSRD-CHERI/cheribuild) to easily get set up (the `cheribuild.py` step will take a very long time the first time): unless you're lucky enough to have access to a physical Morello board, there is the issue of actually using a CHERI implementation. for this article I will be making use of the [QEMU](https://en.wikipedia.org/wiki/QEMU) emulator to emulate a [RISC-V](https://en.wikipedia.org/wiki/RISC-V) CHERI environment. running [CheriBSD](https://www.cheribsd.org/) on this emulator will allow us to have a nice [FreeBSD](https://www.freebsd.org/)-based capability-enabled environment to play around with. I'll use [cheribuild](https://github.com/CTSRD-CHERI/cheribuild) to easily get set up (the `cheribuild.py` step will take a very long time the first time):
{% highlight console %} ```console
$ sudo apt install autoconf automake libtool pkg-config clang bison cmake \ $ sudo apt install autoconf automake libtool pkg-config clang bison cmake \
ninja-build samba flex texinfo time libglib2.0-dev libpixman-1-dev \ ninja-build samba flex texinfo time libglib2.0-dev libpixman-1-dev \
libarchive-dev libarchive-tools libbz2-dev libattr1-dev libcap-ng-dev libarchive-dev libarchive-tools libbz2-dev libattr1-dev libcap-ng-dev
@ -140,21 +150,23 @@ CheriBSD/riscv (cheribsd-riscv64-purecap) (ttyu0)
login: root login: root
root@cheribsd-riscv64-purecap:~ # root@cheribsd-riscv64-purecap:~ #
{% endhighlight %} ```
now we have our shell inside our CheriBSD emulated platform, we can start to try things out. let's compile our `membug` program again, this time with the toolchain targetting CheriBSD RISC-V - this will have been built as part of the dependencies already. once it's built, we can `scp` it over to the CheriBSD filesystem, as we set up the SSH forwarding port to now we have our shell inside our CheriBSD emulated platform, we can start to try things out. let's compile our `membug` program again, this time with the toolchain targetting CheriBSD RISC-V - this will have been built as part of the dependencies already.
`1111`.
{% highlight console %} once our `membug-cheribsd` executable is built, we can `scp` it over to the CheriBSD filesystem. remember, we set up the SSH forwarding port to `1111`.
# on a separate terminal on your host machine
from a terminal on your host machine:
```console
$ ~/cheri/output/sdk/utils/cheribsd-riscv64-purecap-clang membug.c -Wall -g -fno-stack-protector -o membug-cheribsd $ ~/cheri/output/sdk/utils/cheribsd-riscv64-purecap-clang membug.c -Wall -g -fno-stack-protector -o membug-cheribsd
$ scp -P 2222 ./membug-cheribsd root@localhost:~/ $ scp -P 2222 ./membug-cheribsd root@localhost:~/
{% endhighlight %} ```
and now we can see what happens when we explore our bug with CHERI: and now we can see what happens when we explore our bug with CHERI:
{% highlight console %} ```console
$./membug-cheribsd $ ./membug-cheribsd
enter your name: jack enter your name: jack
hello jack hello jack
my_perfect_string: what a beautiful string my_perfect_string: what a beautiful string
@ -162,12 +174,12 @@ my_perfect_string: what a beautiful string
$ ./membug-cheribsd $ ./membug-cheribsd
enter your name: Hubert Blaine Wolfeschlegelsteinhausenbergerdorff Sr. enter your name: Hubert Blaine Wolfeschlegelsteinhausenbergerdorff Sr.
In-address space security exception (core dumped) In-address space security exception (core dumped)
{% endhighlight %} ```
it's working! we are getting a capability fault as we exceed the bounds of the it's working! we are getting a capability fault as we exceed the bounds of the
`user_name` capability bounds. we can use gdb to verify this is caused by the bounds fault: `user_name` capability bounds. we can use gdb to verify this is caused by the bounds fault:
{% highlight plaintext linenos %} ```gdb
(gdb) run (gdb) run
Starting program: /root/membug-cheribsd Starting program: /root/membug-cheribsd
enter your name: Hubert Blaine Wolfeschlegelsteinhausenbergerdorff Sr. enter your name: Hubert Blaine Wolfeschlegelsteinhausenbergerdorff Sr.
@ -177,11 +189,12 @@ Capability bounds fault caused by register ca6.
0x0000000040314ce8 in memcpy (dst0=0x3fffdfff44, src0=<optimized out>, length=54) at /home/jack/cheri/cheribsd/lib/libc/string/bcopy.c:143 0x0000000040314ce8 in memcpy (dst0=0x3fffdfff44, src0=<optimized out>, length=54) at /home/jack/cheri/cheribsd/lib/libc/string/bcopy.c:143
(gdb) p $ca6 (gdb) p $ca6
$1 = () 0x3fffdfff78 [rwRW,0x3fffdfff44-0x3fffdfff64] $1 = () 0x3fffdfff78 [rwRW,0x3fffdfff44-0x3fffdfff64]
{% endhighlight %} ```
as we can see, the bounds for our `user_name` capability (which is stored in capability register `ca6`) are `0x3fffdfff44-0x3fffdfff64`, but the address is `0x3fffdfff78`. this is out of the bounds allowed by the capability, so the architecture throws a fault. if we look at the assembly generated by the compiler, we can see it set our capability bounds to a size of 32 to enforce this behaviour: as we can see, the bounds for our `user_name` capability (which is stored in capability register `ca6`) are `0x3fffdfff44-0x3fffdfff64`, but the address is `0x3fffdfff78`. this is out of the bounds allowed by the capability, so the architecture throws a fault. if we look at the assembly generated by the compiler, we can see it set our capability bounds to a size of 32 to enforce this behaviour:
{% highlight armasm linenos %}0000000000001ce8 <main>: ```asm
0000000000001ce8 <main>:
; int main() { ; int main() {
cincoffset csp, csp, -160 cincoffset csp, csp, -160
csc cra, 144 (csp) csc cra, 144 (csp)
@ -198,28 +211,67 @@ as we can see, the bounds for our `user_name` capability (which is stored in cap
mv a1, zero mv a1, zero
csd a1, -104 (cs0) csd a1, -104 (cs0)
csw a1, 0 (ca2) csw a1, 0 (ca2)
{% endhighlight %} ```
### capability monotonicity ### chains of capabilities
at this point you may be thinking "okay, that's great, but if we can just set the bounds of a capability with an instruction then what's the point? surely I can just set global bounds on some random pointer and access whatever I want?" at this point you may be thinking "okay, that's great, but if we can just set the bounds of a capability with an instruction then what's the point? surely I can just set global bounds on some random pointer and access whatever I want?"
fundamental to the idea of capabilities is their _provenance_ and _monotonicity_. simply put, the first says we can only construct a capability using specific instructions, from an existing capability. we can't just create a capability from some random number. let's see what happens when we try to run our `ptrs_as_numbers` program on CheriBSD: fundamental to the idea of capabilities is their *provenance* and *monotonicity*.
{% highlight plaintext %} *provenance*, simply put, means we can only construct a capability from an existing capability, using specific instructions. we can't just create a capability from some random `size_t` and use it to load/store something. let's see what happens when we try to run our `ptrs_as_numbers` program on CheriBSD:
(gdb) runStarting program: /root/ptrs_as_numbers-cheribsd
```gdb
(gdb) run
Starting program: /root/ptrs_as_numbers-cheribsd
*x=1234 *x=1234
Program received signal SIGPROT, CHERI protection violation.Capability tag fault caused by register ca1.0x0000000000101c66 in main () at ptrs_as_numbers.c:1414 printf("*x=%d\n", *x); Program received signal SIGPROT, CHERI protection violation.
Capability tag fault caused by register ca1.
0x0000000000101c66 in main () at ptrs_as_numbers.c:1414
printf("*x=%d\n", *x);
(gdb) p $ca1 (gdb) p $ca1
$1 = () 0x3fffdfff74 $1 = () 0x3fffdfff74
{% endhighlight %} ```
we can see we get a fault - the tag isn't set. any capability with a tag not set to 1 cannot be dereferenced - it is invalid. in fact, this capability has no capability metadata - when we copied it into our `unsigned long`, we just copied the 64-bit address. we get a fault, because the tag isn't set. any capability with a tag not set to 1 cannot be dereferenced -- it is invalid. in fact, this capability has no capability metadata -- when we copied it into our `unsigned long`, we just copied the 64-bit address.
*monotonicity* is what stops us taking an existing capability, and creating a capability with more permissions and/or access than the original. it stipulates that when we create a capability from another capability (which we have to do - provenance), the permissions and bounds of the new capability must be equal to or less than the original. so our bounds can only get narrower as we create new capabilites from an existing capability. this means that capabilities trace back in a chain - they are all created from other capabilities, and narrowed as necessary. in this case, (simplified) when the kernel loads our program it will give us capabilities that are wide enough to do everything we need to do, and the compiler will try and make sure all the capabilities that we make and use from these are as tightly bound and unpermissive as possible. *monotonicity* is what stops us taking an existing capability and creating a capability with more permissions and/or access than the original. it stipulates that when we create a capability from another capability (which we have to do -- provenance), the permissions and bounds of the new capability must be less than or equal to the original. so our bounds can only get narrower as we create new capabilites from an existing capability. this means that capabilities trace back in a chain - they are all created from other capabilities, and narrowed as necessary. in this case, (simplified) when the kernel loads our program it will give us capabilities that are wide enough to do everything we need to do, and the compiler will try and make sure all the capabilities that we make and use from these are as tightly bound and unpermissive as possible.
### CHERI-fying code ### CHERI-fying code
you'll notice we got a lot of these benefits "for free". we only had to recompile our code, and we got this extra security. of course, CHERI does require changes to programs. naturally, the compiler had to be changed a lot to implement this behaviour. it also especially requires changes to things like the C library and kernel in order to take advantage of the features fully. sufficiently large userspace programs do need changes too. one common issue is that a lot of existing C code assumes that `sizeof (*void) == sizeof(size_t)`. with CHERI, our pointers are now twice as big. however, `size_t` hasn't changed size, as the address space size hasn't changed - for example, if we index into an array with `size_t`, the index should still be the same size; the extra data in our `void *` capability is the metadata, not extra address data. any program that tries to convert from some `unsigned long` or `size_t` to a capability will fault - this violates provenance. so, sometimes code changes have to be made to ensure we are keeping the capability metadata around. you'll notice we got a lot of these benefits "for free". we only had to recompile our code, and we gained this extra security. of course, CHERI does require changes to program sources. naturally, the compiler was changed a lot to implement this behaviour. in particular, CHERI also requires changes to things like the C library and kernel in order to take advantage of the features fully. sufficiently large userspace programs will generally require source changes.
one common issue is that a lot of existing C code assumes that `sizeof (*void) == sizeof(size_t)`. with CHERI, our pointers are now twice as big. however, `size_t` hasn't changed size, as the address space size hasn't changed - for example, if we index into an array with `size_t`, the index should still be the same size; the extra data in our `void *` capability is the metadata, not extra address data. any program that tries to convert from some `unsigned long` or `size_t` to a capability will fault - this violates provenance. so, sometimes code changes have to be made to ensure we are keeping the capability metadata around. in CHERI, we can use `ptraddr_t` to store addresses and `[u]intptr_t` to store capabilities.
let's make a program to see some differences in types, and demonstrate how `uintptr_t` can preserve capabilities:
{{ code(path="cheri/ptrtypes.c", syntax="c", linenos=true) }}
running this on our non-CHERI host will give us:
```console
$ ./ptrtypes
type size (hex) size (dec)
=====================================
uintptr_t 0x08 08
size_t 0x08 08
void* 0x08 08
=====================================
```
running this on CHERI (64-bit):
```console
$ ./ptrtypes-cheribsd
type size (hex) size (dec)
=====================================
ptraddr_t 0x08 08
uintptr_t 0x10 16
size_t 0x08 08
void* 0x10 16
=====================================
*b: 888
*b: 111
*b: 999
```
## epilogue ## epilogue
I appreciate this has been a fragmented and surface level introduction to CHERI. hopefully it has provided some education in some basic aims of CHERI regardless. potential benefits and uses for CHERI go much deeper than anything I've touched on here, so please, read more about everything - and get your hands dirty trying out messing about with qemu and CheriBSD! I appreciate this has been a fragmented and surface level introduction to CHERI. hopefully it has provided some education in some basic aims of CHERI regardless. potential benefits and uses for CHERI go much deeper than anything I've touched on here, so please, read more about everything - and get your hands dirty trying out messing about with qemu and CheriBSD!

View File

@ -1,7 +1,9 @@
--- +++
layout: post-sensor-watch title = "sensor watch"
title: "sensor watch" date = 2022-11-14
--- template = "article-sw.html"
+++
## preamble ## preamble
some time back I was browsing [Crowd Supply](https://www.crowdsupply.com/) when I came across [the Sensor Watch project](https://www.crowdsupply.com/oddly-specific-objects/sensor-watch) by [Joey Castillo](https://github.com/joeycastillo). I had wanted some kind of "hackable" watch for a while, and had looked at things like [Watchy](https://www.crowdsupply.com/sqfmi/watchy), but this project hit the sweet spot for me. I love my existing F91-W, and this project was a good combination of open source with community software support. one key feature that was important to me is battery life - the Sensor Watch battery life in an average usage scenario is so long that [Joey's is still going strong](https://twitter.com/josecastillo/status/1590066358351298560)! some time back I was browsing [Crowd Supply](https://www.crowdsupply.com/) when I came across [the Sensor Watch project](https://www.crowdsupply.com/oddly-specific-objects/sensor-watch) by [Joey Castillo](https://github.com/joeycastillo). I had wanted some kind of "hackable" watch for a while, and had looked at things like [Watchy](https://www.crowdsupply.com/sqfmi/watchy), but this project hit the sweet spot for me. I love my existing F91-W, and this project was a good combination of open source with community software support. one key feature that was important to me is battery life - the Sensor Watch battery life in an average usage scenario is so long that [Joey's is still going strong](https://twitter.com/josecastillo/status/1590066358351298560)!
@ -22,7 +24,8 @@ this part was out of stock everywhere I initially looked (the usual contenders f
### PCB and stencil ### PCB and stencil
for the PCB I opted to go with [JLCPCB](https://jlcpcb.com/). I simply uploaded the relevant gerbers, and adjusted the necessary settings. notably, [the thickness should be 0.6mm](https://github.com/joeycastillo/Sensor-Watch/issues/14#issuecomment-922974276">) - this does narrow the choice of manufacturer (for example, OSH Park doesn't go this thin). I haven't yet ordered any sensor board PCBs, but [PCBWay](https://www.pcbway.com/) seems to be *the* option there. The PCB turned out great, although the silkscreen is a little hard to read at this size due to lack of sharpness: for the PCB I opted to go with [JLCPCB](https://jlcpcb.com/). I simply uploaded the relevant gerbers, and adjusted the necessary settings. notably, [the thickness should be 0.6mm](https://github.com/joeycastillo/Sensor-Watch/issues/14#issuecomment-922974276">) - this does narrow the choice of manufacturer (for example, OSH Park doesn't go this thin). I haven't yet ordered any sensor board PCBs, but [PCBWay](https://www.pcbway.com/) seems to be *the* option there. The PCB turned out great, although the silkscreen is a little hard to read at this size due to lack of sharpness:
{% picture jpt-webp sensor-watch/pcb.jpg --alt a closeup of a sensor watch PCB %}
{{ image(path="images/sensor-watch/pcb.jpg", alt="a closeup of a green sensor watch PCB") }}
## assembly ## assembly
@ -43,7 +46,8 @@ the assembly process is as follows:
[removing the buzzer connector from your old PCB and soldering it onto the back of the Sensor Watch PCB.](https://youtu.be/Zr0pKeC2VFU?t=185) this will feel blissfully easy after the button! you also have to place the battery clip, but no soldering needed here :). [removing the buzzer connector from your old PCB and soldering it onto the back of the Sensor Watch PCB.](https://youtu.be/Zr0pKeC2VFU?t=185) this will feel blissfully easy after the button! you also have to place the battery clip, but no soldering needed here :).
one area I found particularly difficult was the area with the oscillator crystal and the two 0402 capacitors, C7 and C8. things are a bit cramped here, so extra care was needed: one area I found particularly difficult was the area with the oscillator crystal and the two 0402 capacitors, C7 and C8. things are a bit cramped here, so extra care was needed:
{% picture jpt-webp sensor-watch/c7c8.jpg --alt a closeup of a sensor watch PCB, with an area circled. the area contains some small, and closely grouped pads %}
{{ image(path="images/sensor-watch/c7c8.jpg", alt="a closeup of a green sensor watch PCB, with an area circled. the area contains some small, and closely grouped copper pads") }}
## software ## software
@ -95,8 +99,6 @@ some summary thoughts:
- if you have a Sensor Watch (or are planning to!) please go ahead and [contribute to movement](https://github.com/joeycastillo/Sensor-Watch) if you have a cool idea. I'm sure some reviews would be helpful to spot any issues on existing PRs before a maintainer gets to them to save some time. - if you have a Sensor Watch (or are planning to!) please go ahead and [contribute to movement](https://github.com/joeycastillo/Sensor-Watch) if you have a cool idea. I'm sure some reviews would be helpful to spot any issues on existing PRs before a maintainer gets to them to save some time.
- the one issue I've had with using my Sensor Watch for TOTP is clock accuracy. the clock drifts over time, so I have to set the time once or twice a week to keep it nice and accurate for the TOTP functionality to be nice to use. but a community member is working on this, and it's going to get a lot better. check out the Discord channel to see some seriously cool engineering going into this calibration effort. - the one issue I've had with using my Sensor Watch for TOTP is clock accuracy. the clock drifts over time, so I have to set the time once or twice a week to keep it nice and accurate for the TOTP functionality to be nice to use. but a community member is working on this, and it's going to get a lot better. check out the Discord channel to see some seriously cool engineering going into this calibration effort.
{{ image(path="images/sensor-watch/watch1.jpg", alt="a shot of a yellow and black assembled sensor watch, lying horizontally on a surface") }}
{% picture sensor-watch/watch1.jpg --alt a shot of a yellow and black assembled sensor watch, lying horizontally on a surface %} {{ image(path="images/sensor-watch/watch2.jpg", alt="a shot of a yellow and black assembled sensor watch, lying vertically on a surface") }}
{% picture sensor-watch/watch2.jpg --alt a shot of a yellow and black assembled sensor watch, lying vertically on a surface %} {{ image(path="images/sensor-watch/wrist.jpg", alt="a shot of a yellow and black assembled sensor watch, on the author's wrist") }}
{% picture sensor-watch/wrist.jpg --alt a shot of a yellow and black assembled sensor watch, on the author's wrist %}

BIN
cv.pdf

Binary file not shown.

View File

@ -1,55 +0,0 @@
\documentclass[letterpaper,11pt]{article}
% Choose bibliography style for formatting list of publications
\usepackage[style=ieee,url=false,doi=false,maxbibnames=99,sorting=ydnt,dashed=false]{biblatex}
\bibliography{papers}
% Choose theme, e.g. black, RedViolet, ForestGreen, MidnightBlue
\def\theme{BlueViolet}
% More predefined colors can be found in
% https://en.wikibooks.org/wiki/LaTeX/Colors
% Example photograph taken from Wikimedia Commons
% https://commons.wikimedia.org/wiki/File:Kiara_Krit_passport.jpg
\usepackage{simplecv}
\boldname{Bond-Preston}{Jack}{Mr.}
\begin{document}
\thispagestyle{empty}
% Heading
\headinginline{Jack Bond-Preston}{
Website: \website{jackbondpreston.me} \\
Email: \email{jackbondpreston@outlook.com} \\
LinkedIn: \linkedin{jack-bond-preston-922706150} \\
GitHub: \github{jackbondpreston}
}
% \headingphoto{Name Surname}{
% Website: \website{example.com} \\
% Email: \email{example@example.edu} \\
% LinkedIn: \linkedin{name-surname} \\
% GitHub: \github{example}
% }{photo.jpg}
% Page One
\import{sections/}{education.tex}
\import{sections/}{experience.tex}
%\import{sections/}{publications.tex}
%\pagebreak
% Page Two
%\import{sections/}{teaching.tex}
% \sidebyside
\import{sections/}{skills.tex}
% {\import{sections/}{languages.tex}}
%\import{sections/}{projects.tex}
%\import{sections/}{awards.tex}
%\import{sections/}{extracurricular.tex}
\end{document}

View File

@ -1,20 +0,0 @@
\section{Scholarships and Awards}
\denseouterlist{
\entry{Some Scholarship \hfill 2018\textendash 2020}
\entry{Some Award \hfill 2018\fillyear{\textendash 2018}}
\entry{Some Award \hfill 2017\fillyear{\textendash 2017}}
\entry{Some Award \hfill 2016\fillyear{\textendash 2016}}
\entry{Some Scholarship \hfill 2013\textendash 2018}
\entry{Some Scholarship \hfill 2013\textendash 2018}
\entry{Some Award \hfill 2013\fillyear{\textendash 2013}}
}

View File

@ -1,14 +0,0 @@
\section{Education}
\outerlist{
\entrybig
{\textbf{University of Bristol}}{Bristol, UK}
{BSc in Computer Science (1st Class Hons)}{2017\textendash 2020}
\vspace{-0.75em}
\innerlist{
\entry{Awarded prize for best second-year group software development project.}
}
}

View File

@ -1,45 +0,0 @@
\section{Experience}
\outerlist{
\entrybig
{\textbf{AMD, Inc. (formerly Xilinx)}}{Cambridge, UK}
{Software Engineer in Adaptive and Embedded Computing Group}{2022\textendash Current}
\innerlist{
\entry{Developing AMDs Onload userspace network stack.}
}
\entrybig
{\textbf{Arm Ltd.}}{Cambridge, UK}
{Graduate Software Engineer in Open Source Software Group}{2021\textendash2022}
\innerlist{
\entry{Porting low-level software to the Morello (CHERI) platform.}
\entryextra{Produced patches in C and AArch64 assembly as part of a project porting the open-source C standard library implementation musl to a new prototype platform.}
\entryextra{Ported larger components of the C library, including the memory allocator and POSIX threads. Considered security and hardening against memory safety bugs at every stage of design and implementation.}
\entryextra{Created a minimal test distribution of Linux for use on an Arm Fixed Virtual Platform, with the ability to run userspace applications in pure-capability mode. This provided the framework for adding FVP-based testing to the CI pipeline (alongside existing emulator-based testing) for further proof of functionality.}
\entryextra{Liased with multiple teams to ensure coordination between libc, kernel ABI, compilers and debuggers.}
\entryextra{Provided code review including feedback and improvements for patches developed by others for the musl project.}
}
\entrybig
{\textbf{University of Bristol}}{Bristol, UK}
{Teaching Assistant in Department of Computer Science}{2019\textendash 2020}
\innerlist{
\entry{Delivered and created content for several Computer Science courses, including content involving operating systems, concurrency, and a software engineering project.}
\entryextra{Provided guidance and troubleshooting assistance to students in both in-person and online lab sessions, including for a course in which students develop a basic Armv7-A multitasking kernel.}
\entryextra{Interviewed students in viva-style coursework assessments, and assisted with subsequent coursework marking.}
\entryextra{Assisted with the creation and improvement of lab sheets (including skeleton and solution code).}
}
% \entrybig
% {\textbf{Evolve East Anglia CIC}}{Norwich, UK}
% {Support Worker}{2020\textendash Current}
% \innerlist{
% \entry{Assisting vulnerable adults with transitioning to a permanent living situation after suffering mental difficulties.}
% \entryextra{Handled crises swiftly, independently and effectively.}
% \entryextra{Built upon existing communication skills and knowledge about wellbeing and mental health.}
% }
}

View File

@ -1,22 +0,0 @@
\section{Extracurricular Activities}
\denseouterlist{
\entrymid[\textbullet]
{Member at Some Club}{2017\textendash Current}
{Detailed explanation of what you do at this club}
\entrymid[\textbullet]
{Member at Some Club}{2016\textendash 2017}
{Detailed explanation of what you do at this club}
\entrymid[\textbullet]
{Volunteer at Some Event}{Fall 2019}
{Detailed explanation of what you do in this event}
\entrymid[\textbullet]
{Volunteer at Some Event}{Winter 2015}
{Detailed explanation of what you do in this event}
}

View File

@ -1,7 +0,0 @@
\section{Languages}
\denseouterlist{
\entry{\textbf{English:} Native speaker}
\entry{\textbf{German:} CEFR A2/B1 (Elementary/Low Intermediate)}
}

View File

@ -1,28 +0,0 @@
\section{Projects}
See full list of projects on \website{example.com/projects}
\vspace{1em}
\begin{minipage}[t]{0.505\textwidth}
\outerlist{
\entrybig[\textbullet]
{Project Title (Technology Used, 2019)}{}
{Short explanation of the project}{}
}
\end{minipage}
\begin{minipage}[t]{0.48\textwidth}
\outerlist{
\entrybig[\textbullet]
{Project Title (Technology Used, 2019)}{}
{Short explanation of the project}{}
}
\end{minipage}

View File

@ -1,9 +0,0 @@
\nocite{*}
\printbibliography[title=Publications]
% Can instead manually enter publications as shown:
% \section{Publications}
% \orderedouterlist{
% \entry{S. Petridis, J. Shen, \textbf{D. Cetin} and M. Pantic, "Visual-Only Recognition of Normal, Whispered And Silent Speech", \textit{IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP), April 2018}}
% }

View File

@ -1,11 +0,0 @@
\section{Skills}
\denseouterlist{
\entry{\textbf{Low-Level Software \& Architecture:} C, C++ (inc. 11/17/20 standards), Armv7/8/9 (assembly \& architecture), RISC-V, CHERI, GNU Make, CMake.}
\entry{\textbf{Software Engineering:} Git, Gerrit, Linux, Bash \& Zsh, Python, Java, Haskell, Agile, Jira.}
\entry{\textbf{Web Development:} HTML5, Modern CSS, ECMAScript 2015+ \& Typescript, Vue.js, Spring Boot, SQL.}
\entry{\textbf{Teaching:} Giving lectures \& seminars, interviewing, marking coursework, giving knowledge sharing presentations.}
\entry{\textbf{Design:} 3D modelling, vector graphics, Photoshop.}
}

View File

@ -1,12 +0,0 @@
\section{Teaching}
\denseouterlist{
\entrymid[\textbullet]
{\textbf{Head Teaching Assistant} at University Name}{Spring 2019}{Course Name (COURSE CODE)}
\entrymid[\textbullet]
{\textbf{Teaching Assistant} at University Name}{Spring 2017}{Course Name (COURSE CODE)}
}

View File

@ -1,149 +0,0 @@
\ProvidesPackage{simplecv}
% Packages
\usepackage[cm]{fullpage} % Margins
\usepackage[hidelinks]{hyperref} % Hyperlinks
\usepackage{titlesec} % Title formatting
\usepackage{subfiles} % File importing
\usepackage{multicol} % Multiple columns
\usepackage[usenames,dvipsnames]{xcolor} % Coloring
\usepackage{enumitem} % List customization
\usepackage{lastpage} % Page numbering
\usepackage{fancyhdr} % Footers
\usepackage[russian,english]{babel} % Language styles
\usepackage{graphicx} % Importing graphics
\usepackage[export]{adjustbox} % Aligning margins
% % Chinese
% \usepackage{xeCJK}
% \setCJKmainfont{BabelStone Han}
% % Cyrillic/Russian
% \usepackage{hyphenat}
% \babelfont{rm}{Droid Sans}
% Styling
\pagestyle{fancy}
\fancyhf{}
\renewcommand{\headrulewidth}{0pt}
\renewcommand{\footrulewidth}{0pt}
\urlstyle{same}
\raggedbottom
\raggedright
\setlength{\tabcolsep}{0in}
% Quotes
\usepackage[autostyle,english=american]{csquotes}
\MakeOuterQuote{"}
% Hyperlinks
% \newcommand{\link}[2]{\href{#1}{\underline{\smash{#2}}}}
\newcommand{\link}[2]{\href{#1}{#2}}
% Define colors
\definecolor{color-text}{gray}{0.10} % light black
\definecolor{color-detail}{gray}{0.40} % dark gray
\colorlet{color-title}{\theme} % black
% Set text color
\makeatletter
\newcommand{\globalcolor}[1]{\color{#1}\global\let\default@color\current@color}
\makeatother
\AtBeginDocument{\globalcolor{color-text}}
% Shorthand
\newcommand{\github}[1]{\href{https://github.com/#1/}{github.com/#1}}
\newcommand{\email}[1]{\href{mailto:#1}{#1}}
\newcommand{\website}[1]{\href{https://#1/}{#1}}
\newcommand{\linkedin}[1]{\href{https://www.linkedin.com/in/#1/}{#1}}
% Dummy environment
\newenvironment*{dummyenv}{}{}
% Inline heading
\newcommand{\headinginline}[2]{
\begin{minipage}[t]{0.50\textwidth}
\vspace*{\fill}
\Huge \textcolor{color-title}{#1}
\end{minipage}
\begin{minipage}[t]{0.45\textwidth}
\begin{flushright}
#2
\end{flushright}
\end{minipage}
}
% Photo heading
\newcommand{\headingphoto}[3]{
\begin{minipage}[t]{0.60\textwidth}
\begin{dummyenv}
\vspace*{\fill}
\Huge \textcolor{color-title}{#1}
\end{dummyenv}
\vspace{5mm}\\
#2
\end{minipage}
\begin{minipage}[t]{0.35\textwidth}
\begin{flushright}
\includegraphics[width=.5\linewidth,valign=t]{#3}
\end{flushright}
\end{minipage}
}
% Two-columns
\newcommand{\sidebyside}[2]{
\begin{multicols}{2}
#1 \columnbreak
#2 \end{multicols}
}
% Section titles
\titleformat{\section}{
\scshape\raggedright\Large\color{color-title}}{}{0em}{}[\color{color-title}\titlerule
\vspace{-\smallskipamount}]
% Footer
\fancyfoot[R]{Page \thepage \hspace{1pt} of \pageref{LastPage}}
% Lists
\newcommand{\outerlist}[1]{
\begin{itemize}[leftmargin=*] #1 \end{itemize}}
\newcommand{\denseouterlist}[1]{
\begin{itemize}[leftmargin=*,itemsep=0pt] #1 \end{itemize}}
\newcommand{\innerlist}[1]{
\begin{itemize}[topsep=0pt] #1 \end{itemize}}
\newcommand{\orderedouterlist}[1]{
\begin{enumerate}[leftmargin=*] #1 \end{enumerate}}
% List items
\newcommand{\entry}[1]{\item\small{#1}}
\newcommand{\entryextra}[1]{\textcolor{color-detail}{\entry{#1}}}
\newcommand{\entrylabeled}[2][]{\item[#1]\small{#2}}
\newcommand{\entrymid}[4][]{
\item[#1] \small{#2} \hfill \small{#3}
\vspace{-\smallskipamount} \item[]\small{\textit{#4}}}
\newcommand{\entrybig}[5][]{\item[#1]
\begin{tabular*}{0.97\textwidth}{l@{\extracolsep{\fill}}r}
#2 & #3 \\ {\small#4} & {\small #5} \\ \end{tabular*}}
% Fill year
\newcommand{\fillyear}[1]{\phantom{#1}}
% Make author name bold: https://tex.stackexchange.com/a/327046
\newcommand*{\boldname}[3]{%
\def\lastname{#1}%
\def\firstname{#2}%
\def\firstinit{#3}}
\boldname{}{}{}
\renewcommand{\mkbibnamegiven}[1]{%
\ifboolexpr{ ( test {\ifdefequal{\firstname}{\namepartgiven}} or test {\ifdefequal{\firstinit}{\namepartgiven}} ) and test {\ifdefequal{\lastname}{\namepartfamily}} }
{\mkbibbold{#1}}{#1}%
}
\renewcommand{\mkbibnamefamily}[1]{%
\ifboolexpr{ ( test {\ifdefequal{\firstname}{\namepartgiven}} or test {\ifdefequal{\firstinit}{\namepartgiven}} ) and test {\ifdefequal{\lastname}{\namepartfamily}} }
{\mkbibbold{#1}}{#1}%
}

5
sass/style/_colours.scss Normal file
View File

@ -0,0 +1,5 @@
$background-color: rgb(12, 17, 20);
$body-color: rgb(252, 252, 252);
$heading-color: rgb(255, 182, 193);
$link-color: rgb(252, 169, 184);
$inl-code-color: rgb(165, 214, 255);

79
sass/style/article.scss Normal file
View File

@ -0,0 +1,79 @@
@import "_colours";
.article {
p,
li {
a {
font-weight: normal;
text-decoration: underline;
word-wrap: break-word;
}
code {
color: #a5d6ff;
}
}
picture img,
p img {
max-width: 100%;
display: block;
}
code,
pre {
font-family: "Source Code Pro";
}
pre {
padding: 10px;
overflow: auto;
mark {
display: block;
background-color: rgba(254, 252, 232, 0.9);
}
table {
width: 100%;
border-collapse: collapse;
td {
padding: 0;
}
td:nth-of-type(2) {
padding-left: 15px;
}
td:nth-of-type(1) {
text-align: right;
user-select: none;
padding-right: 10px;
border-right: 3px solid #c0c5ce;
}
}
}
.header-link {
display: inline-block;
}
h1 {
display: flex;
justify-content: space-between;
@media screen and (max-width: 450px) {
display: block;
.home-link {
display: block;
}
}
.home-link {
font-size: 0.5em;
color: $body-color;
}
}
}

93
sass/style/main.scss Normal file
View File

@ -0,0 +1,93 @@
@import "_colours";
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 400;
src: local(''),
url('/fonts/source-code-pro-v22-latin-ext_latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/fonts/source-code-pro-v22-latin-ext_latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 700;
src: local(''),
url('/fonts/source-code-pro-v22-latin-ext_latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/fonts/source-code-pro-v22-latin-ext_latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
@font-face {
font-family: 'Source Code Pro';
font-style: italic;
font-weight: 400;
src: local(''),
url('/fonts/source-code-pro-v22-latin-ext_latin-italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/fonts/source-code-pro-v22-latin-ext_latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
@font-face {
font-family: 'Source Code Pro';
font-style: italic;
font-weight: 700;
src: local(''),
url('/fonts/source-code-pro-v22-latin-ext_latin-700italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('/fonts/source-code-pro-v22-latin-ext_latin-700italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
body {
background-color: $background-color;
color: $body-color;
padding-left: 5vw;
padding-right: 5vw;
padding-top: 5vh;
font-family: 'Source Code Pro';
font-size: 1.5rem;
@media screen and (max-width: 600px) {
font-size: 1rem;
}
}
h1 {
color: $heading-color;
margin: 0;
}
h2 {
margin: 0;
margin-top: 3rem;
margin-bottom: 0.5rem;
}
a {
color: $link-color;
font-weight: bold;
text-decoration: none;
}
li {
line-height: 150%;
}
h2 {
a.header-link {
display: none;
img {
height: 1.25rem;
margin-bottom: -4px;
}
}
a.header-link, a.atom-link {
padding-left: 10px;
font-weight: normal;
font-size: 1.3rem;
}
}
img {
max-width: 100%;
}

View File

@ -0,0 +1,60 @@
body {
padding: 0;
margin: 0;
min-height: 100vh;
}
.wrapper {
display: grid;
grid-template-columns: 30rem auto;
grid-template-rows: auto;
gap: 0;
min-height: 100vh;
}
.article {
padding: 5rem;
padding-bottom: 1rem;
}
.side {
background-image: url(/images/sensor-watch/f91w-strap.svg);
background-repeat: repeat-y;
}
.side>svg {
width: 30rem;
position: fixed;
}
@media only screen and (max-width: 1500px) {
.wrapper {
grid-template-columns: 10rem auto;
grid-template-rows: auto;
}
.side>svg {
width: 10rem;
}
.article {
padding-left: 3rem;
padding-right: 1rem;
padding-top: 1rem;
}
}
@media only screen and (max-width: 800px) {
.side {
display: none;
}
.wrapper {
grid-template-columns: auto;
grid-template-rows: auto;
}
.article {
padding: 1rem;
}
}

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 203 KiB

View File

Before

Width:  |  Height:  |  Size: 294 B

After

Width:  |  Height:  |  Size: 294 B

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

Before

Width:  |  Height:  |  Size: 228 KiB

After

Width:  |  Height:  |  Size: 228 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 MiB

After

Width:  |  Height:  |  Size: 5.2 MiB

View File

Before

Width:  |  Height:  |  Size: 5.6 MiB

After

Width:  |  Height:  |  Size: 5.6 MiB

View File

Before

Width:  |  Height:  |  Size: 6.8 MiB

After

Width:  |  Height:  |  Size: 6.8 MiB

1
syntaxes/console Submodule

@ -0,0 +1 @@
Subproject commit 6a4024043dd6018ccfde1a826e33fe957e647075

View File

@ -0,0 +1 @@
{% if level == 2 %}<a href="#{{ id }}" aria-label="Anchor link for: {{ id }}" class="header-link">[<img src="/images/link.svg" />]</a>{% endif %}

137
templates/article-sw.html Normal file
View File

@ -0,0 +1,137 @@
{% extends "base.html" %}
{% block extra_head %}
<link rel="stylesheet" href="/style/article.css">
<link rel="stylesheet" href="/style/sensor-watch.css">
{% endblock %}
{% block content %}
<div class="wrapper">
<div class="side">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 500">
<defs>
<style>
.cls-1 {
fill: #0c1113;
}
.cls-2 {
fill: none;
stroke: #f6b4c1;
stroke-miterlimit: 10;
stroke-width: 2px;
}
.cls-3 {
fill: #f6b4c1;
}
</style>
</defs>
<g id="Layer_5" data-name="Layer 5">
<rect class="cls-1" width="300" height="500" />
</g>
<g id="Layer_1" data-name="Layer 1">
<path class="cls-2"
d="M150,335.07c-21-.18-53.88.56-76.78-1-1.15.37-6.4-1.85-7.11-3.33-11.43-13.68-14.6-19.62-14.67-31.33-1-13-1.27-26.4-2-49.34" />
<path class="cls-2"
d="M150,329.83c-20.3-.19-49.15.57-71.32-1-1.12.37-7.19-1.87-7.89-3.38-11.06-13.86-13.12-19.87-13.19-31.74-.92-13.2-1-20.39-1.73-43.63" />
<path class="cls-2"
d="M150,352.07S59.42,351,58.31,350.52s-20.67-32.89-21.11-34-2.89-66.45-2.89-66.45" />
<path class="cls-2"
d="M150,364.3s-93.23-1-94.34-1.42S28.31,318.3,27.86,317.19s-2.65-67.12-2.65-67.12" />
<polyline class="cls-2" points="27.68 315.07 20.48 310.24 17.14 264.91 25.21 257.91" />
<path class="cls-2"
d="M150,335.07c21-.18,53.87.56,76.78-1,1.15.37,6.39-1.85,7.11-3.33,11.43-13.68,14.6-19.62,14.67-31.33.94-13,1.26-26.4,2-49.34" />
<path class="cls-2"
d="M150,329.83c20.29-.19,49.15.57,71.32-1,1.11.37,7.19-1.87,7.88-3.38,11.06-13.86,13.13-19.87,13.2-31.74.91-13.2,1-20.39,1.73-43.63" />
<path class="cls-2"
d="M150,352.07s90.56-1.11,91.67-1.55,20.66-32.89,21.11-34,2.89-66.45,2.89-66.45" />
<path class="cls-2"
d="M150,364.3s93.22-1,94.33-1.42,27.34-44.58,27.78-45.69,2.65-67.12,2.65-67.12" />
<polyline class="cls-2" points="272.29 315.07 279.5 310.24 282.83 264.91 274.76 257.91" />
<path class="cls-2"
d="M150,165c-21,.19-53.88-.56-76.78,1-1.15-.36-6.4,1.85-7.11,3.33C54.66,183,51.49,189,51.42,200.67c-1,13-1.27,26.39-2,49.33" />
<path class="cls-2"
d="M150,170.24c-20.3.19-49.15-.56-71.32,1-1.12-.36-7.19,1.88-7.89,3.38-11.06,13.86-13.12,19.88-13.19,31.74-.92,13.21-1,20.39-1.73,43.63" />
<path class="cls-2" d="M150,148s-90.56,1.11-91.67,1.56-20.67,32.88-21.11,34S34.31,250,34.31,250" />
<path class="cls-2"
d="M150,135.78s-93.23,1-94.34,1.41-27.33,44.59-27.78,45.7S25.21,250,25.21,250" />
<polyline class="cls-2" points="27.68 185 20.48 189.83 17.14 235.17 25.21 242.17" />
<path class="cls-2"
d="M150,165c21,.19,53.87-.56,76.78,1,1.15-.36,6.39,1.85,7.11,3.33,11.43,13.69,14.6,19.62,14.67,31.34.94,13,1.26,26.39,2,49.33" />
<path class="cls-2"
d="M150,170.24c20.29.19,49.15-.56,71.32,1,1.11-.36,7.19,1.88,7.88,3.38,11.06,13.86,13.13,19.88,13.2,31.74.91,13.21,1,20.39,1.73,43.63" />
<path class="cls-2" d="M150,148s90.56,1.11,91.67,1.56,20.66,32.88,21.11,34S265.67,250,265.67,250" />
<path class="cls-2"
d="M150,135.78s93.22,1,94.33,1.41,27.34,44.59,27.78,45.7S274.76,250,274.76,250" />
<polyline class="cls-2" points="272.29 185 279.5 189.83 282.83 235.17 274.76 242.17" />
</g>
<g id="Layer_3" data-name="Layer 3">
<path class="cls-2"
d="M224.67,250c-.35,3.5,1,31.12-1.07,33.66-1.35,4.06-5.75,5.94-9.78,5.9H86.51c-4,0-8.43-1.84-9.77-5.9-2-2.3-.74-30.41-1.07-33.66.35-3.58-.92-20.74,1.07-23.77,1.34-4.06,5.75-5.95,9.77-5.9H213.82c4,0,8.43,1.84,9.78,5.9C225.57,229.27,224.35,246.4,224.67,250Z"
id="screen" />
<path class="cls-2"
d="M229.33,247.11c-.36,4.09,1,36.37-1.13,39.33-1.43,4.75-6.09,6.95-10.35,6.89H83c-4.26.06-8.92-2.14-10.35-6.89-2.13-2.69-.78-35.53-1.13-39.33.37-4.19-1-24.23,1.13-27.77,1.43-4.75,6.09-7,10.35-6.89H217.85c4.26-.06,8.92,2.14,10.35,6.89C230.28,222.89,229,242.91,229.33,247.11Z" />
<g id="CASIO">
<path class="cls-2"
d="M97.31,181.28a3.36,3.36,0,0,0-.2-1.34,1.91,1.91,0,0,0-.44-.63,3.49,3.49,0,0,0-1.28-.31c-.36-.06-1.72-.14-2.14-.14a20.79,20.79,0,0,0-3.11.17c-.14.14-.72.28-.89.5a2.43,2.43,0,0,0-.47,1.16v1.78c0,.47-.06,1.84,0,2a2.64,2.64,0,0,0,.53,1.06,3,3,0,0,0,1.22.44,23.26,23.26,0,0,0,2.8.09,23.2,23.2,0,0,0,2.42,0,1.9,1.9,0,0,0,1.06-.41,1.32,1.32,0,0,0,.5-1.05,4.25,4.25,0,0,1,0-.78" />
<path class="cls-2"
d="M100,186.71c0-1.13,3.1-5.88,3.69-7.25a1.45,1.45,0,0,1,.23-.47c.17-.16.35-.14.93-.13s.64,0,.73.16c.75,1.48,2.61,5.22,3,5.9a4.31,4.31,0,0,1,.79,1.79" />
<line class="cls-2" x1="101.07" y1="184.13" x2="108.15" y2="184.13" />
<path class="cls-2"
d="M120,180.36c.15-2.21-2.17-1.64-4.08-1.67-1,0-2.47,0-2.75.36-1.37,1-1.23,3.06.74,3.41,1.57.31,4.21-.33,5.5.07,1.56.79,1.58,3.44-.5,3.55-1.56-.08-6.23.93-6.63-1.5" />
<path class="cls-2" d="M123.92,177.83s.14,6.61,0,9.13" />
<path class="cls-2"
d="M128.06,182.59a6.3,6.3,0,0,0,.11,2.08c.25.5.86,1.35,1.52,1.4s3.31,0,3.31,0a25.08,25.08,0,0,0,2.61,0c.28-.1.92-.1,1.06-.68s.3-.66.27-1.26-.08-2.19-.08-2.19a13.37,13.37,0,0,0,0-1.92,1.37,1.37,0,0,0-.59-.92,14.78,14.78,0,0,0-1.53-.39H132a12.52,12.52,0,0,0-2.3,0c-.28.14-.95.19-1.17.5a2.33,2.33,0,0,0-.41,1.19C128.11,180.79,128.06,182.59,128.06,182.59Z" />
</g>
<g id="F-91W">
<path class="cls-2"
d="M167.94,186.22a18.32,18.32,0,0,1,.64-2.94s.56-2.79.64-2.95a45.6,45.6,0,0,1,5.34,0" />
<path class="cls-2" d="M173.06,183.28c-.92-.11-4.48,0-4.48,0" />
<path class="cls-2" d="M176.69,183.85c2,.15,3-.31,5.25,0" />
<path class="cls-2"
d="M186.39,184.94c.84,1.58,3.78.91,4.83,0,1.69-2.54,1.8-4.89-2-4.55-6.28,1.92,2.2,5.1,3.06,1.13" />
<path class="cls-2"
d="M197.39,186.83c.09-1.6.57-2.3.92-4.25a13.46,13.46,0,0,0,.63-2.83c.09,2.21-2,2-3.58,1.92" />
<path class="cls-2"
d="M204.08,179.75s0,3.52.06,4,.12,1.9.12,1.9h1.16s1.52-2.69,1.86-3.44a4.41,4.41,0,0,1,.52-1l.32-.59,1.25,0s0,.21,0,.93-.09,3.95-.09,3.95h1.35l.41-.68c.27-.46,2.39-3.53,2.39-5.11" />
</g>
<path class="cls-2" d="M18.29,211.06H10.53s-1.46-.81-1.46,8.11c0,8.42,2.17,7.78,2.17,7.78h6.34"
onmouseover="document.getElementById('screen').style.fill='blue';"
onmouseleave="document.getElementById('screen').style.fill='none';" />
<path class="cls-2" d="M18.29,288.94H10.53s-1.46.81-1.46-8.11c0-8.42,2.17-7.78,2.17-7.78h6.34" />
<path class="cls-2" d="M281.71,288.94h7.76s1.46.81,1.46-8.11c0-8.42-2.17-7.78-2.17-7.78h-6.34" />
</g>
<g id="Layer_4" data-name="Layer 4">
<path class="cls-2"
d="M150,306.44H125.88c-1.36,0-2,.2-2.44.84-.28.44-.28.44-.56,1.94a24.24,24.24,0,0,0,0,6.59,9.45,9.45,0,0,0,2.39,4.66c1.22,1,3.81,3.56,5.47,3.61s19.25,0,19.25,0" />
<polygon class="cls-3"
points="63.43 307.26 118.99 307.26 118.99 309.26 63.91 309.26 63.43 307.26" />
<polyline class="cls-2" points="149.99 110.44 63.43 110.44 55.66 137.19" />
<polygon class="cls-3"
points="62.63 195.75 149.99 195.75 149.99 193.75 63.11 193.75 62.63 195.75" />
<line class="cls-2" x1="65.99" y1="110.44" x2="65.99" />
<line class="cls-2" x1="65.99" y1="389.42" x2="65.99" y2="500" />
<polyline class="cls-2" points="149.99 389.42 63.43 389.42 55.66 362.67" />
<path class="cls-2"
d="M150,306.44h24.11c1.36,0,2,.2,2.45.84.27.44.27.44.55,1.94a24.24,24.24,0,0,1,0,6.59,9.45,9.45,0,0,1-2.39,4.66c-1.22,1-3.8,3.56-5.47,3.61s-19.25,0-19.25,0" />
<polygon class="cls-3" points="236.56 307.26 181 307.26 181 309.26 236.08 309.26 236.56 307.26" />
<polyline class="cls-2" points="150 110.44 236.56 110.44 244.33 137.19" />
<polygon class="cls-3" points="237.36 195.75 150 195.75 150 193.75 236.89 193.75 237.36 195.75" />
<line class="cls-2" x1="234" y1="110.44" x2="234" />
<line class="cls-2" x1="234" y1="389.42" x2="234" y2="500" />
<polyline class="cls-2" points="150 389.42 236.56 389.42 244.33 362.67" />
</g>
</svg>
</div>
<div class="article">
<h1><a href="{{ page.permalink }}">{{ page.title }}</a></a><span class="home-link">[ <a href="/">homepage</a> ]</span></h1>
{{ page.content | safe }}
<hr>
<p><a href="mailto:jackbondpreston@outlook.com">email me</a> to have a conversation</p>
</div>
</div>
{% endblock %}

17
templates/article.html Normal file
View File

@ -0,0 +1,17 @@
{% extends "base.html" %}
{% block extra_head %}
<link rel="stylesheet" href="/style/article.css">
{% endblock %}
{% block content %}
<div class="article">
<h1><a href="{{ page.permalink }}">{{ page.title }}</a><span class="home-link">[ <a href="/">homepage</a> ]</span></h1>
{{ page.content | safe }}
<hr>
<p><a href="mailto:jackbondpreston@outlook.com">email me</a> to have a conversation</p>
</div>
{% endblock content %}

26
templates/base.html Normal file
View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<!--
  l、
゙(゚、 。
 l、゙ ~ヽ
 じしf_, )
-->
<html lang="en-GB">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<title>{% block title %} {% endblock %}</title>
<link rel="stylesheet" href="/style/main.css">
{% block extra_head %} {% endblock %}
</head>
<body>
{% block content %} {% endblock %}
</body>
</html>

13
templates/index.html Normal file
View File

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block title %}{{ section.title }}{% endblock title %}
{% block content %}
{{ section.content | safe }}
<ul>
{% for page in section.pages %}
<li><a href="{{ page.permalink | safe }}">[{{ page.date }}] {{ page.title }}</a></li>
{% endfor %}
</ul>
{% endblock content %}

View File

@ -0,0 +1,4 @@
{% set code = load_data(path="code/" ~ path) -%}
```{% if syntax %}{{ syntax }}{% endif %}{% if linenos %}, linenos{% endif %}
{{ code }}
```

View File

@ -0,0 +1,5 @@
{% set image = resize_image(path=path, width=1024, height=1024, op="fit", format="webp") %}
{% set url = get_url(path=path) %}
<a href="{{ url }}">
<img src="{{ image.url }}"{% if alt %} alt="{{ alt }}"{% endif %} />
</a>