Skip to content

Commit

Permalink
Add support for kernel != userland snapd in seccomp
Browse files Browse the repository at this point in the history
The old C code supported the following cases for compat syscalls:

1. kernel and userspace are both 32 bit (no compat)
2. kernel and userspace are both 64 bit (need to load 32 bit arch for
   32 bit compat)
3. kernel is 64 bit and userspace is 32 bit (need to load 64 bit arch
   for native syscalls)

This commit ensures case (3) is now also supported with the new
go based seccomp code.

Note that (3) in the context of snaps is very strange. When snapd
runs as a 32bit app it will only request 32bit snaps from the
store. So there has to be 32bit snaps that contain 64bit code and
logic that can auto-detect if 64 bit code can be run and that then
makes use of this 64bit code.
  • Loading branch information
mvo5 committed Jun 19, 2017
1 parent b9c5004 commit 205c52a
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 4 deletions.
46 changes: 45 additions & 1 deletion arch/arch.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package arch
import (
"log"
"runtime"
"syscall"
)

// ArchitectureType is the type for a supported snappy architecture
Expand Down Expand Up @@ -66,7 +67,50 @@ func ubuntuArchFromGoArch(goarch string) string {

ubuntuArch := goArchMapping[goarch]
if ubuntuArch == "" {
log.Panicf("unknown goarch %v", goarch)
log.Panicf("unknown goarch %q", goarch)
}

return ubuntuArch
}

// UbuntuKernelArchitecture return the debian equivalent architecture
// for the current running kernel. This is usually the same as the
// UbuntuArchitecture - however there maybe cases that you run e.g.
// a snapd:i386 on an amd64 kernel.
func UbuntuKernelArchitecture() string {
var utsname syscall.Utsname
if err := syscall.Uname(&utsname); err != nil {
log.Panicf("cannot get kernel architecture: %v", err)
}

kernelArch := make([]byte, 0, len(utsname.Machine))
for _, c := range utsname.Machine {
if c == 0 {
break
}
kernelArch = append(kernelArch, byte(c))
}

return ubuntuArchFromKernelArch(string(kernelArch))
}

// ubuntuArchFromkernelArch maps the kernel architecture as reported
// via uname() to the dpkg architecture
func ubuntuArchFromKernelArch(utsMachine string) string {
kernelArchMapping := map[string]string{
// kernel ubuntu
"i686": "i386",
"x86_64": "amd64",
"armv7": "armhf",
"aarch64": "arm64",
"ppc64le": "ppc64el",
"s390x": "s390x",
"ppc": "powerpc",
}

ubuntuArch := kernelArchMapping[utsMachine]
if ubuntuArch == "" {
log.Panicf("unknown kernel arch %q", utsMachine)
}

return ubuntuArch
Expand Down
42 changes: 39 additions & 3 deletions cmd/snap-seccomp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,14 +489,50 @@ func parseLine(line string, secFilter *seccomp.ScmpFilter) error {
// the kernel arch to support the kernel's arch (eg, 64bit kernels with
// 32bit userspace).
func addSecondaryArches(secFilter *seccomp.ScmpFilter) error {
switch arch.UbuntuArchitecture() {
// note that all architecture strings are in the dpkg
// architecture notation
var compatArch string

// common case: kernel and userspace have the same arch. We
// add a compat architecture for some architectures that
// support it, e.g. on amd64 kernel and userland, we add
// compat i386 syscalls.
if arch.UbuntuArchitecture() == arch.UbuntuKernelArchitecture() {
switch arch.UbuntuArchitecture() {
case "amd64":
compatArch = "i386"
case "arm64":
compatArch = "armhf"
case "ppc64el":
compatArch = "powerpc"
}
} else {
// less common case, kernel and userspace
// different. This can happen when running e.g. a
// amd64 kernel with a i386 userland. However in this
// case snapd would also only request i386 snaps. So
// the use-case is even stranger, a i386 snap would
// have to ship some 64bit code that would have to
// detect at runtime if it can be used or not.
compatArch = arch.UbuntuKernelArchitecture()
}

// actually add the compat architecture (if we need one)
switch compatArch {
case "amd64":
return secFilter.AddArch(seccomp.ArchX86)
return secFilter.AddArch(seccomp.ArchAMD64)
case "arm64":
return secFilter.AddArch(seccomp.ArchARM)
return secFilter.AddArch(seccomp.ArchARM64)
case "ppc64el":
return secFilter.AddArch(seccomp.ArchPPC64LE)
case "i386":
return secFilter.AddArch(seccomp.ArchX86)
case "armhf":
return secFilter.AddArch(seccomp.ArchARM)
case "powerpc":
return secFilter.AddArch(seccomp.ArchPPC)
}

return nil
}

Expand Down

0 comments on commit 205c52a

Please sign in to comment.