Compare commits
	
		
			No commits in common. "21735a8abe25b7b01720e3dabaa0cb51dd1a178e" and "7106b0096863e89e1a6809d8c2bed78adf6a3ba5" have entirely different histories.
		
	
	
		
			21735a8abe
			...
			7106b00968
		
	
		
							
								
								
									
										50
									
								
								.gitea/workflows/build.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								.gitea/workflows/build.yml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
			
		||||
name: Build
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  - push
 | 
			
		||||
  - pull_request
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  dist:
 | 
			
		||||
    name: Create distribution
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
 | 
			
		||||
 | 
			
		||||
      - name: Install Nix
 | 
			
		||||
        uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30
 | 
			
		||||
        with:
 | 
			
		||||
          # explicitly enable sandbox
 | 
			
		||||
          install_options: --daemon
 | 
			
		||||
          extra_nix_config: |
 | 
			
		||||
            sandbox = true
 | 
			
		||||
            system-features = nixos-test benchmark big-parallel kvm
 | 
			
		||||
          enable_kvm: true
 | 
			
		||||
 | 
			
		||||
      - name: Ensure environment
 | 
			
		||||
        run: >-
 | 
			
		||||
          apt-get update && apt-get install -y sqlite3
 | 
			
		||||
        if: ${{ runner.os == 'Linux' }}
 | 
			
		||||
 | 
			
		||||
      - name: Restore Nix store
 | 
			
		||||
        uses: nix-community/cache-nix-action@v5
 | 
			
		||||
        with:
 | 
			
		||||
          primary-key: nix-small-${{ runner.os }}-${{ hashFiles('**/*.nix') }}
 | 
			
		||||
          restore-prefixes-first-match: nix-small-${{ runner.os }}-
 | 
			
		||||
 | 
			
		||||
      - name: Build for test
 | 
			
		||||
        id: build-test
 | 
			
		||||
        run: >-
 | 
			
		||||
          export FORTIFY_REV="$(git rev-parse --short HEAD)" &&
 | 
			
		||||
          sed -i.old 's/version = /version = "0.0.0-'$FORTIFY_REV'"; # version = /' package.nix &&
 | 
			
		||||
          nix build --print-out-paths --print-build-logs .#dist &&
 | 
			
		||||
          mv package.nix.old package.nix &&
 | 
			
		||||
          echo "rev=$FORTIFY_REV" >> $GITHUB_OUTPUT
 | 
			
		||||
 | 
			
		||||
      - name: Upload test build
 | 
			
		||||
        uses: actions/upload-artifact@v3
 | 
			
		||||
        with:
 | 
			
		||||
          name: "fortify-${{ steps.build-test.outputs.rev }}"
 | 
			
		||||
          path: result/*
 | 
			
		||||
          retention-days: 1
 | 
			
		||||
@ -5,7 +5,7 @@ on:
 | 
			
		||||
  - pull_request
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  test:
 | 
			
		||||
  tests:
 | 
			
		||||
    name: Run NixOS test
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
@ -30,13 +30,8 @@ jobs:
 | 
			
		||||
      - name: Restore Nix store
 | 
			
		||||
        uses: nix-community/cache-nix-action@v5
 | 
			
		||||
        with:
 | 
			
		||||
          primary-key: flake-check-${{ runner.os }}-${{ hashFiles('**/*.nix') }}
 | 
			
		||||
          restore-prefixes-first-match: flake-check-${{ runner.os }}-
 | 
			
		||||
          gc-max-store-size-linux: 1073741824
 | 
			
		||||
          purge: true
 | 
			
		||||
          purge-prefixes: flake-check-${{ runner.os }}-
 | 
			
		||||
          purge-created: 60
 | 
			
		||||
          purge-primary-key: never
 | 
			
		||||
          primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix') }}
 | 
			
		||||
          restore-prefixes-first-match: nix-${{ runner.os }}-
 | 
			
		||||
 | 
			
		||||
      - name: Run tests
 | 
			
		||||
        run: |
 | 
			
		||||
@ -46,55 +41,6 @@ jobs:
 | 
			
		||||
      - name: Upload test output
 | 
			
		||||
        uses: actions/upload-artifact@v3
 | 
			
		||||
        with:
 | 
			
		||||
          name: "nixos-vm-output"
 | 
			
		||||
          path: result/*
 | 
			
		||||
          retention-days: 1
 | 
			
		||||
 | 
			
		||||
  dist:
 | 
			
		||||
    name: Create distribution
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
 | 
			
		||||
 | 
			
		||||
      - name: Install Nix
 | 
			
		||||
        uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30
 | 
			
		||||
        with:
 | 
			
		||||
          # explicitly enable sandbox
 | 
			
		||||
          install_options: --daemon
 | 
			
		||||
          extra_nix_config: |
 | 
			
		||||
            sandbox = true
 | 
			
		||||
            system-features = nixos-test benchmark big-parallel kvm
 | 
			
		||||
          enable_kvm: true
 | 
			
		||||
 | 
			
		||||
      - name: Ensure environment
 | 
			
		||||
        run: >-
 | 
			
		||||
          apt-get update && apt-get install -y sqlite3
 | 
			
		||||
        if: ${{ runner.os == 'Linux' }}
 | 
			
		||||
 | 
			
		||||
      - name: Restore Nix store
 | 
			
		||||
        uses: nix-community/cache-nix-action@v5
 | 
			
		||||
        with:
 | 
			
		||||
          primary-key: build-dist-${{ runner.os }}-${{ hashFiles('**/*.nix') }}
 | 
			
		||||
          restore-prefixes-first-match: build-dist-${{ runner.os }}-
 | 
			
		||||
          gc-max-store-size-linux: 1073741824
 | 
			
		||||
          purge: true
 | 
			
		||||
          purge-prefixes: build-dist-${{ runner.os }}-
 | 
			
		||||
          purge-created: 60
 | 
			
		||||
          purge-primary-key: never
 | 
			
		||||
 | 
			
		||||
      - name: Build for test
 | 
			
		||||
        id: build-test
 | 
			
		||||
        run: >-
 | 
			
		||||
          export FORTIFY_REV="$(git rev-parse --short HEAD)" &&
 | 
			
		||||
          sed -i.old 's/version = /version = "0.0.0-'$FORTIFY_REV'"; # version = /' package.nix &&
 | 
			
		||||
          nix build --print-out-paths --print-build-logs .#dist &&
 | 
			
		||||
          mv package.nix.old package.nix &&
 | 
			
		||||
          echo "rev=$FORTIFY_REV" >> $GITHUB_OUTPUT
 | 
			
		||||
 | 
			
		||||
      - name: Upload test build
 | 
			
		||||
        uses: actions/upload-artifact@v3
 | 
			
		||||
        with:
 | 
			
		||||
          name: "fortify-${{ steps.build-test.outputs.rev }}"
 | 
			
		||||
          name: "result"
 | 
			
		||||
          path: result/*
 | 
			
		||||
          retention-days: 1
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,7 @@ struct f_syscall_act {
 | 
			
		||||
#define LEN(arr) (sizeof(arr) / sizeof((arr)[0]))
 | 
			
		||||
 | 
			
		||||
#define SECCOMP_RULESET_ADD(ruleset) do {                                                                      \
 | 
			
		||||
  if (opts & F_VERBOSE) F_println("adding seccomp ruleset \"" #ruleset "\"");                                  \
 | 
			
		||||
  F_println("adding seccomp ruleset \"" #ruleset "\""); \
 | 
			
		||||
  for (int i = 0; i < LEN(ruleset); i++) {                                                                     \
 | 
			
		||||
    assert(ruleset[i].m_errno == EPERM || ruleset[i].m_errno == ENOSYS);                                       \
 | 
			
		||||
                                                                                                               \
 | 
			
		||||
@ -89,31 +89,6 @@ int32_t f_export_bpf(int fd, uint32_t arch, uint32_t multiarch, f_syscall_opts o
 | 
			
		||||
    {SCMP_SYS(migrate_pages), EPERM},
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // fortify: project-specific extensions
 | 
			
		||||
  struct f_syscall_act deny_common_ext[] = {
 | 
			
		||||
    // system calls for changing the system clock
 | 
			
		||||
    {SCMP_SYS(adjtimex), EPERM},
 | 
			
		||||
    {SCMP_SYS(clock_adjtime), EPERM},
 | 
			
		||||
    {SCMP_SYS(clock_adjtime64), EPERM},
 | 
			
		||||
    {SCMP_SYS(clock_settime), EPERM},
 | 
			
		||||
    {SCMP_SYS(clock_settime64), EPERM},
 | 
			
		||||
    {SCMP_SYS(settimeofday), EPERM},
 | 
			
		||||
 | 
			
		||||
    // loading and unloading of kernel modules
 | 
			
		||||
    {SCMP_SYS(delete_module), EPERM},
 | 
			
		||||
    {SCMP_SYS(finit_module), EPERM},
 | 
			
		||||
    {SCMP_SYS(init_module), EPERM},
 | 
			
		||||
 | 
			
		||||
    // system calls for rebooting and reboot preparation
 | 
			
		||||
    {SCMP_SYS(kexec_file_load), EPERM},
 | 
			
		||||
    {SCMP_SYS(kexec_load), EPERM},
 | 
			
		||||
    {SCMP_SYS(reboot), EPERM},
 | 
			
		||||
 | 
			
		||||
    // system calls for enabling/disabling swap devices
 | 
			
		||||
    {SCMP_SYS(swapoff), EPERM},
 | 
			
		||||
    {SCMP_SYS(swapon), EPERM},
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  struct f_syscall_act deny_ns[] = {
 | 
			
		||||
    // Don't allow subnamespace setups:
 | 
			
		||||
    {SCMP_SYS(unshare), EPERM},
 | 
			
		||||
@ -151,34 +126,6 @@ int32_t f_export_bpf(int fd, uint32_t arch, uint32_t multiarch, f_syscall_opts o
 | 
			
		||||
    {SCMP_SYS(mount_setattr), ENOSYS},
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // fortify: project-specific extensions
 | 
			
		||||
  struct f_syscall_act deny_ns_ext[] = {
 | 
			
		||||
    // changing file ownership
 | 
			
		||||
    {SCMP_SYS(chown), EPERM},
 | 
			
		||||
    {SCMP_SYS(chown32), EPERM},
 | 
			
		||||
    {SCMP_SYS(fchown), EPERM},
 | 
			
		||||
    {SCMP_SYS(fchown32), EPERM},
 | 
			
		||||
    {SCMP_SYS(fchownat), EPERM},
 | 
			
		||||
    {SCMP_SYS(lchown), EPERM},
 | 
			
		||||
    {SCMP_SYS(lchown32), EPERM},
 | 
			
		||||
 | 
			
		||||
    // system calls for changing user ID and group ID credentials
 | 
			
		||||
    {SCMP_SYS(setgid), EPERM},
 | 
			
		||||
    {SCMP_SYS(setgid32), EPERM},
 | 
			
		||||
    {SCMP_SYS(setgroups), EPERM},
 | 
			
		||||
    {SCMP_SYS(setgroups32), EPERM},
 | 
			
		||||
    {SCMP_SYS(setregid), EPERM},
 | 
			
		||||
    {SCMP_SYS(setregid32), EPERM},
 | 
			
		||||
    {SCMP_SYS(setresgid), EPERM},
 | 
			
		||||
    {SCMP_SYS(setresgid32), EPERM},
 | 
			
		||||
    {SCMP_SYS(setresuid), EPERM},
 | 
			
		||||
    {SCMP_SYS(setresuid32), EPERM},
 | 
			
		||||
    {SCMP_SYS(setreuid), EPERM},
 | 
			
		||||
    {SCMP_SYS(setreuid32), EPERM},
 | 
			
		||||
    {SCMP_SYS(setuid), EPERM},
 | 
			
		||||
    {SCMP_SYS(setuid32), EPERM},
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  struct f_syscall_act deny_tty[] = {
 | 
			
		||||
    // Don't allow faking input to the controlling tty (CVE-2017-5226)
 | 
			
		||||
    {SCMP_SYS(ioctl), EPERM, &SCMP_A1(SCMP_CMP_MASKED_EQ, 0xFFFFFFFFu, (int)TIOCSTI)},
 | 
			
		||||
@ -198,22 +145,6 @@ int32_t f_export_bpf(int fd, uint32_t arch, uint32_t multiarch, f_syscall_opts o
 | 
			
		||||
    {SCMP_SYS(ptrace), EPERM}
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  struct f_syscall_act deny_emu[] = {
 | 
			
		||||
    // modify_ldt is a historic source of interesting information leaks,
 | 
			
		||||
    // so it's disabled as a hardening measure.
 | 
			
		||||
    // However, it is required to run old 16-bit applications
 | 
			
		||||
    // as well as some Wine patches, so it's allowed in multiarch.
 | 
			
		||||
    {SCMP_SYS(modify_ldt), EPERM},
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // fortify: project-specific extensions
 | 
			
		||||
  struct f_syscall_act deny_emu_ext[] = {
 | 
			
		||||
    {SCMP_SYS(subpage_prot), ENOSYS},
 | 
			
		||||
    {SCMP_SYS(switch_endian), ENOSYS},
 | 
			
		||||
    {SCMP_SYS(vm86), ENOSYS},
 | 
			
		||||
    {SCMP_SYS(vm86old), ENOSYS},
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // Blocklist all but unix, inet, inet6 and netlink
 | 
			
		||||
  struct
 | 
			
		||||
  {
 | 
			
		||||
@ -268,11 +199,26 @@ int32_t f_export_bpf(int fd, uint32_t arch, uint32_t multiarch, f_syscall_opts o
 | 
			
		||||
  if (opts & F_DENY_NS) SECCOMP_RULESET_ADD(deny_ns);
 | 
			
		||||
  if (opts & F_DENY_TTY) SECCOMP_RULESET_ADD(deny_tty);
 | 
			
		||||
  if (opts & F_DENY_DEVEL) SECCOMP_RULESET_ADD(deny_devel);
 | 
			
		||||
  if (!allow_multiarch) SECCOMP_RULESET_ADD(deny_emu);
 | 
			
		||||
  if (opts & F_EXT) {
 | 
			
		||||
    SECCOMP_RULESET_ADD(deny_common_ext);
 | 
			
		||||
    if (opts & F_DENY_NS) SECCOMP_RULESET_ADD(deny_ns_ext);
 | 
			
		||||
    if (!allow_multiarch) SECCOMP_RULESET_ADD(deny_emu_ext);
 | 
			
		||||
 | 
			
		||||
  if (!allow_multiarch) {
 | 
			
		||||
    F_println("disabling modify_ldt");
 | 
			
		||||
 | 
			
		||||
    // modify_ldt is a historic source of interesting information leaks,
 | 
			
		||||
    // so it's disabled as a hardening measure.
 | 
			
		||||
    // However, it is required to run old 16-bit applications
 | 
			
		||||
    // as well as some Wine patches, so it's allowed in multiarch.
 | 
			
		||||
    ret = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(modify_ldt), 0);
 | 
			
		||||
 | 
			
		||||
    // See above for the meaning of EFAULT.
 | 
			
		||||
    if (ret == -EFAULT) {
 | 
			
		||||
      // call fmsg here?
 | 
			
		||||
      res = 4;
 | 
			
		||||
      goto out;
 | 
			
		||||
    } else if (ret < 0) {
 | 
			
		||||
      res = 5;
 | 
			
		||||
      errno = -ret;
 | 
			
		||||
      goto out;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Socket filtering doesn't work on e.g. i386, so ignore failures here
 | 
			
		||||
@ -8,15 +8,13 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
  F_VERBOSE    = 1 << 0,
 | 
			
		||||
  F_EXT        = 1 << 1,
 | 
			
		||||
  F_DENY_NS    = 1 << 2,
 | 
			
		||||
  F_DENY_TTY   = 1 << 3,
 | 
			
		||||
  F_DENY_DEVEL = 1 << 4,
 | 
			
		||||
  F_MULTIARCH  = 1 << 5,
 | 
			
		||||
  F_LINUX32    = 1 << 6,
 | 
			
		||||
  F_CAN        = 1 << 7,
 | 
			
		||||
  F_BLUETOOTH  = 1 << 8,
 | 
			
		||||
  F_DENY_NS    = 1 << 0,
 | 
			
		||||
  F_DENY_TTY   = 1 << 1,
 | 
			
		||||
  F_DENY_DEVEL = 1 << 2,
 | 
			
		||||
  F_MULTIARCH  = 1 << 3,
 | 
			
		||||
  F_LINUX32    = 1 << 4,
 | 
			
		||||
  F_CAN        = 1 << 5,
 | 
			
		||||
  F_BLUETOOTH  = 1 << 6,
 | 
			
		||||
} f_syscall_opts;
 | 
			
		||||
 | 
			
		||||
extern void F_println(char *v);
 | 
			
		||||
							
								
								
									
										95
									
								
								helper/bwrap/seccomp-resolve.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								helper/bwrap/seccomp-resolve.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,95 @@
 | 
			
		||||
package bwrap
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/internal/fmsg"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SyscallPolicy struct {
 | 
			
		||||
	DenyDevel bool `json:"deny_devel"`
 | 
			
		||||
	Multiarch bool `json:"multiarch"`
 | 
			
		||||
	Linux32   bool `json:"linux32"`
 | 
			
		||||
	Can       bool `json:"can"`
 | 
			
		||||
	Bluetooth bool `json:"bluetooth"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type seccompBuilder struct {
 | 
			
		||||
	config *Config
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *seccompBuilder) Len() int {
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return 2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *seccompBuilder) Append(args *[]string, extraFiles *[]*os.File) error {
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if f, err := s.config.resolveSeccomp(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else {
 | 
			
		||||
		extraFile(args, extraFiles, positionalArgs[Seccomp], f)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) resolveSeccomp() (*os.File, error) {
 | 
			
		||||
	if c.Syscall == nil {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// resolve seccomp filter opts
 | 
			
		||||
	var (
 | 
			
		||||
		opts    syscallOpts
 | 
			
		||||
		optd    []string
 | 
			
		||||
		optCond = [...]struct {
 | 
			
		||||
			v bool
 | 
			
		||||
			o syscallOpts
 | 
			
		||||
			d string
 | 
			
		||||
		}{
 | 
			
		||||
			{!c.UserNS, flagDenyNS, "denyns"},
 | 
			
		||||
			{c.NewSession, flagDenyTTY, "denytty"},
 | 
			
		||||
			{c.Syscall.DenyDevel, flagDenyDevel, "denydevel"},
 | 
			
		||||
			{c.Syscall.Multiarch, flagMultiarch, "multiarch"},
 | 
			
		||||
			{c.Syscall.Linux32, flagLinux32, "linux32"},
 | 
			
		||||
			{c.Syscall.Can, flagCan, "can"},
 | 
			
		||||
			{c.Syscall.Bluetooth, flagBluetooth, "bluetooth"},
 | 
			
		||||
		}
 | 
			
		||||
	)
 | 
			
		||||
	if CPrintln != nil {
 | 
			
		||||
		optd = make([]string, 1, len(optCond)+1)
 | 
			
		||||
		optd[0] = "common"
 | 
			
		||||
	}
 | 
			
		||||
	for _, opt := range optCond {
 | 
			
		||||
		if opt.v {
 | 
			
		||||
			opts |= opt.o
 | 
			
		||||
			if fmsg.Verbose() {
 | 
			
		||||
				optd = append(optd, opt.d)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if CPrintln != nil {
 | 
			
		||||
		CPrintln(fmt.Sprintf("seccomp flags: %s", optd))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// export seccomp filter to tmpfile
 | 
			
		||||
	if f, err := tmpfile(); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	} else {
 | 
			
		||||
		return f, exportAndSeek(f, opts)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func exportAndSeek(f *os.File, opts syscallOpts) error {
 | 
			
		||||
	if err := exportFilter(f.Fd(), opts); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err := f.Seek(0, io.SeekStart)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
@ -1,90 +1,83 @@
 | 
			
		||||
package bwrap
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
#cgo linux pkg-config: --static libseccomp
 | 
			
		||||
 | 
			
		||||
#include "seccomp-export.h"
 | 
			
		||||
*/
 | 
			
		||||
import "C"
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/helper/seccomp"
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/internal/fmsg"
 | 
			
		||||
	"runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SyscallPolicy struct {
 | 
			
		||||
	// disable fortify extensions
 | 
			
		||||
	Compat bool `json:"compat"`
 | 
			
		||||
	// deny development syscalls
 | 
			
		||||
	DenyDevel bool `json:"deny_devel"`
 | 
			
		||||
	// deny multiarch/emulation syscalls
 | 
			
		||||
	Multiarch bool `json:"multiarch"`
 | 
			
		||||
	// allow PER_LINUX32
 | 
			
		||||
	Linux32 bool `json:"linux32"`
 | 
			
		||||
	// allow AF_CAN
 | 
			
		||||
	Can bool `json:"can"`
 | 
			
		||||
	// allow AF_BLUETOOTH
 | 
			
		||||
	Bluetooth bool `json:"bluetooth"`
 | 
			
		||||
var CPrintln func(v ...any)
 | 
			
		||||
 | 
			
		||||
var resErr = [...]error{
 | 
			
		||||
	0: nil,
 | 
			
		||||
	1: errors.New("seccomp_init failed"),
 | 
			
		||||
	2: errors.New("seccomp_arch_add failed"),
 | 
			
		||||
	3: errors.New("seccomp_arch_add failed (multiarch)"),
 | 
			
		||||
	4: errors.New("internal libseccomp failure"),
 | 
			
		||||
	5: errors.New("seccomp_rule_add failed"),
 | 
			
		||||
	6: errors.New("seccomp_export_bpf failed"),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type seccompBuilder struct {
 | 
			
		||||
	config *Config
 | 
			
		||||
type (
 | 
			
		||||
	syscallOpts = C.f_syscall_opts
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	flagDenyNS    syscallOpts = C.F_DENY_NS
 | 
			
		||||
	flagDenyTTY   syscallOpts = C.F_DENY_TTY
 | 
			
		||||
	flagDenyDevel syscallOpts = C.F_DENY_DEVEL
 | 
			
		||||
	flagMultiarch syscallOpts = C.F_MULTIARCH
 | 
			
		||||
	flagLinux32   syscallOpts = C.F_LINUX32
 | 
			
		||||
	flagCan       syscallOpts = C.F_CAN
 | 
			
		||||
	flagBluetooth syscallOpts = C.F_BLUETOOTH
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func tmpfile() (*os.File, error) {
 | 
			
		||||
	fd, err := C.f_tmpfile_fd()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return os.NewFile(uintptr(fd), "tmpfile"), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *seccompBuilder) Len() int {
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return 2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *seccompBuilder) Append(args *[]string, extraFiles *[]*os.File) error {
 | 
			
		||||
	if s == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if f, err := s.config.resolveSeccomp(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else {
 | 
			
		||||
		extraFile(args, extraFiles, positionalArgs[Seccomp], f)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) resolveSeccomp() (*os.File, error) {
 | 
			
		||||
	if c.Syscall == nil {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// resolve seccomp filter opts
 | 
			
		||||
func exportFilter(fd uintptr, opts syscallOpts) error {
 | 
			
		||||
	var (
 | 
			
		||||
		opts    seccomp.SyscallOpts
 | 
			
		||||
		optd    []string
 | 
			
		||||
		optCond = [...]struct {
 | 
			
		||||
			v bool
 | 
			
		||||
			o seccomp.SyscallOpts
 | 
			
		||||
			d string
 | 
			
		||||
		}{
 | 
			
		||||
			{!c.Syscall.Compat, seccomp.FlagExt, "fortify"},
 | 
			
		||||
			{!c.UserNS, seccomp.FlagDenyNS, "denyns"},
 | 
			
		||||
			{c.NewSession, seccomp.FlagDenyTTY, "denytty"},
 | 
			
		||||
			{c.Syscall.DenyDevel, seccomp.FlagDenyDevel, "denydevel"},
 | 
			
		||||
			{c.Syscall.Multiarch, seccomp.FlagMultiarch, "multiarch"},
 | 
			
		||||
			{c.Syscall.Linux32, seccomp.FlagLinux32, "linux32"},
 | 
			
		||||
			{c.Syscall.Can, seccomp.FlagCan, "can"},
 | 
			
		||||
			{c.Syscall.Bluetooth, seccomp.FlagBluetooth, "bluetooth"},
 | 
			
		||||
		}
 | 
			
		||||
		arch      C.uint32_t = 0
 | 
			
		||||
		multiarch C.uint32_t = 0
 | 
			
		||||
	)
 | 
			
		||||
	if seccomp.CPrintln != nil {
 | 
			
		||||
		optd = make([]string, 1, len(optCond)+1)
 | 
			
		||||
		optd[0] = "common"
 | 
			
		||||
	}
 | 
			
		||||
	for _, opt := range optCond {
 | 
			
		||||
		if opt.v {
 | 
			
		||||
			opts |= opt.o
 | 
			
		||||
			if fmsg.Verbose() {
 | 
			
		||||
				optd = append(optd, opt.d)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if seccomp.CPrintln != nil {
 | 
			
		||||
		seccomp.CPrintln(fmt.Sprintf("seccomp flags: %s", optd))
 | 
			
		||||
	switch runtime.GOARCH {
 | 
			
		||||
	case "386":
 | 
			
		||||
		arch = C.SCMP_ARCH_X86
 | 
			
		||||
	case "amd64":
 | 
			
		||||
		arch = C.SCMP_ARCH_X86_64
 | 
			
		||||
		multiarch = C.SCMP_ARCH_X86
 | 
			
		||||
	case "arm":
 | 
			
		||||
		arch = C.SCMP_ARCH_ARM
 | 
			
		||||
	case "arm64":
 | 
			
		||||
		arch = C.SCMP_ARCH_AARCH64
 | 
			
		||||
		multiarch = C.SCMP_ARCH_ARM
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return seccomp.Export(opts)
 | 
			
		||||
	res, err := C.f_export_bpf(C.int(fd), arch, multiarch, opts)
 | 
			
		||||
	if re := resErr[res]; re != nil {
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			return re
 | 
			
		||||
		}
 | 
			
		||||
		return fmt.Errorf("%s: %v", re.Error(), err)
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//export F_println
 | 
			
		||||
func F_println(v *C.char) {
 | 
			
		||||
	if CPrintln != nil {
 | 
			
		||||
		CPrintln(C.GoString(v))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,17 +0,0 @@
 | 
			
		||||
package seccomp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Export(opts SyscallOpts) (f *os.File, err error) {
 | 
			
		||||
	if f, err = tmpfile(); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if err = exportFilter(f.Fd(), opts); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	_, err = f.Seek(0, io.SeekStart)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
@ -1,89 +0,0 @@
 | 
			
		||||
package seccomp
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
#cgo linux pkg-config: --static libseccomp
 | 
			
		||||
 | 
			
		||||
#include "seccomp-export.h"
 | 
			
		||||
*/
 | 
			
		||||
import "C"
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var CPrintln func(v ...any)
 | 
			
		||||
 | 
			
		||||
var resErr = [...]error{
 | 
			
		||||
	0: nil,
 | 
			
		||||
	1: errors.New("seccomp_init failed"),
 | 
			
		||||
	2: errors.New("seccomp_arch_add failed"),
 | 
			
		||||
	3: errors.New("seccomp_arch_add failed (multiarch)"),
 | 
			
		||||
	4: errors.New("internal libseccomp failure"),
 | 
			
		||||
	5: errors.New("seccomp_rule_add failed"),
 | 
			
		||||
	6: errors.New("seccomp_export_bpf failed"),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SyscallOpts = C.f_syscall_opts
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	flagVerbose   SyscallOpts = C.F_VERBOSE
 | 
			
		||||
	FlagExt       SyscallOpts = C.F_EXT
 | 
			
		||||
	FlagDenyNS    SyscallOpts = C.F_DENY_NS
 | 
			
		||||
	FlagDenyTTY   SyscallOpts = C.F_DENY_TTY
 | 
			
		||||
	FlagDenyDevel SyscallOpts = C.F_DENY_DEVEL
 | 
			
		||||
	FlagMultiarch SyscallOpts = C.F_MULTIARCH
 | 
			
		||||
	FlagLinux32   SyscallOpts = C.F_LINUX32
 | 
			
		||||
	FlagCan       SyscallOpts = C.F_CAN
 | 
			
		||||
	FlagBluetooth SyscallOpts = C.F_BLUETOOTH
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func tmpfile() (*os.File, error) {
 | 
			
		||||
	fd, err := C.f_tmpfile_fd()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return os.NewFile(uintptr(fd), "tmpfile"), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func exportFilter(fd uintptr, opts SyscallOpts) error {
 | 
			
		||||
	var (
 | 
			
		||||
		arch      C.uint32_t = 0
 | 
			
		||||
		multiarch C.uint32_t = 0
 | 
			
		||||
	)
 | 
			
		||||
	switch runtime.GOARCH {
 | 
			
		||||
	case "386":
 | 
			
		||||
		arch = C.SCMP_ARCH_X86
 | 
			
		||||
	case "amd64":
 | 
			
		||||
		arch = C.SCMP_ARCH_X86_64
 | 
			
		||||
		multiarch = C.SCMP_ARCH_X86
 | 
			
		||||
	case "arm":
 | 
			
		||||
		arch = C.SCMP_ARCH_ARM
 | 
			
		||||
	case "arm64":
 | 
			
		||||
		arch = C.SCMP_ARCH_AARCH64
 | 
			
		||||
		multiarch = C.SCMP_ARCH_ARM
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// this removes repeated transitions between C and Go execution
 | 
			
		||||
	// when producing log output via F_println and CPrintln is nil
 | 
			
		||||
	if CPrintln != nil {
 | 
			
		||||
		opts |= flagVerbose
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res, err := C.f_export_bpf(C.int(fd), arch, multiarch, opts)
 | 
			
		||||
	if re := resErr[res]; re != nil {
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			return re
 | 
			
		||||
		}
 | 
			
		||||
		return fmt.Errorf("%s: %v", re.Error(), err)
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//export F_println
 | 
			
		||||
func F_println(v *C.char) {
 | 
			
		||||
	if CPrintln != nil {
 | 
			
		||||
		CPrintln(C.GoString(v))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -8,7 +8,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/fst"
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/helper"
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/helper/seccomp"
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/helper/bwrap"
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/internal"
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/internal/fmsg"
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/internal/proc"
 | 
			
		||||
@ -128,7 +128,7 @@ func Main() {
 | 
			
		||||
 | 
			
		||||
	helper.BubblewrapName = payload.Exec[0] // resolved bwrap path by parent
 | 
			
		||||
	if fmsg.Verbose() {
 | 
			
		||||
		seccomp.CPrintln = fmsg.Println
 | 
			
		||||
		bwrap.CPrintln = fmsg.Println
 | 
			
		||||
	}
 | 
			
		||||
	if b, err := helper.NewBwrap(
 | 
			
		||||
		conf, innerInit,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								main.go
									
									
									
									
									
								
							@ -16,7 +16,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/dbus"
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/fst"
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/helper/seccomp"
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/helper/bwrap"
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/internal"
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/internal/app"
 | 
			
		||||
	"git.gensokyo.uk/security/fortify/internal/fmsg"
 | 
			
		||||
@ -310,7 +310,7 @@ func runApp(config *fst.Config) {
 | 
			
		||||
	ctx, cancel := context.WithCancel(context.Background())
 | 
			
		||||
 | 
			
		||||
	if fmsg.Verbose() {
 | 
			
		||||
		seccomp.CPrintln = fmsg.Println
 | 
			
		||||
		bwrap.CPrintln = fmsg.Println
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// handle signals for graceful shutdown
 | 
			
		||||
 | 
			
		||||
@ -118,8 +118,7 @@ in
 | 
			
		||||
                          env
 | 
			
		||||
                          ;
 | 
			
		||||
                        syscall = {
 | 
			
		||||
                          inherit (app) compat multiarch bluetooth;
 | 
			
		||||
                          deny_devel = !app.devel;
 | 
			
		||||
                          inherit (app) devel multiarch bluetooth;
 | 
			
		||||
                        };
 | 
			
		||||
                        map_real_uid = app.mapRealUid;
 | 
			
		||||
                        no_new_session = app.tty;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										26
									
								
								options.md
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								options.md
									
									
									
									
									
								
							@ -36,7 +36,7 @@ package
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
*Default:*
 | 
			
		||||
` <derivation fortify-0.2.12> `
 | 
			
		||||
` <derivation fortify-0.2.11> `
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -198,30 +198,6 @@ null or string
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## environment\.fortify\.apps\.\*\.compat
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Whether to enable disable syscall filter extensions\.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
*Type:*
 | 
			
		||||
boolean
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
*Default:*
 | 
			
		||||
` false `
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
*Example:*
 | 
			
		||||
` true `
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## environment\.fortify\.apps\.\*\.dbus\.session
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -151,7 +151,6 @@ in
 | 
			
		||||
                default = true;
 | 
			
		||||
              };
 | 
			
		||||
 | 
			
		||||
              compat = mkEnableOption "disable syscall filter extensions";
 | 
			
		||||
              devel = mkEnableOption "development kernel APIs";
 | 
			
		||||
              multiarch = mkEnableOption "multiarch kernel support";
 | 
			
		||||
              bluetooth = mkEnableOption "AF_BLUETOOTH socket operations";
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@
 | 
			
		||||
 | 
			
		||||
buildGoModule rec {
 | 
			
		||||
  pname = "fortify";
 | 
			
		||||
  version = "0.2.12";
 | 
			
		||||
  version = "0.2.11";
 | 
			
		||||
 | 
			
		||||
  src = builtins.path {
 | 
			
		||||
    name = "fortify-src";
 | 
			
		||||
@ -63,7 +63,7 @@ buildGoModule rec {
 | 
			
		||||
    makeBinaryWrapper
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  preBuild = ''
 | 
			
		||||
  preConfigure = ''
 | 
			
		||||
    HOME=$(mktemp -d) go generate ./...
 | 
			
		||||
  '';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								test.nix
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								test.nix
									
									
									
									
									
								
							@ -237,8 +237,8 @@ nixosTest {
 | 
			
		||||
    machine.succeed("rm -rf /tmp/src && cp -a '${self.packages.${system}.fortify.src}' /tmp/src")
 | 
			
		||||
    machine.succeed("fortify-fhs -c '(cd /tmp/src && go generate ./... && go test ./... && touch /tmp/success-gotest)' &> /tmp/gotest &")
 | 
			
		||||
 | 
			
		||||
    # To check fortify's version:
 | 
			
		||||
    print(machine.succeed("sudo -u alice -i fortify version"))
 | 
			
		||||
    # To check sway's version:
 | 
			
		||||
    print(machine.succeed("sway --version"))
 | 
			
		||||
 | 
			
		||||
    # Wait for Sway to complete startup:
 | 
			
		||||
    machine.wait_for_file("/run/user/1000/wayland-1")
 | 
			
		||||
@ -254,11 +254,6 @@ nixosTest {
 | 
			
		||||
    print(machine.succeed("sudo -u alice -i fortify -v run -a 0 touch /tmp/success-bare"))
 | 
			
		||||
    machine.wait_for_file("/tmp/fortify.1000/tmpdir/0/success-bare")
 | 
			
		||||
 | 
			
		||||
    # Verify silent output permissive defaults:
 | 
			
		||||
    output = machine.succeed("sudo -u alice -i fortify run -a 0 true &>/dev/stdout")
 | 
			
		||||
    if output != "":
 | 
			
		||||
        raise Exception(f"unexpected output\n{output}")
 | 
			
		||||
 | 
			
		||||
    # Start fortify permissive defaults within Wayland session:
 | 
			
		||||
    fortify('-v run --wayland --dbus notify-send -a "NixOS Tests" "Test notification" "Notification from within sandbox." && touch /tmp/dbus-done')
 | 
			
		||||
    machine.wait_for_file("/tmp/dbus-done")
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,17 @@
 | 
			
		||||
#include "wayland-bind.h"
 | 
			
		||||
package wl
 | 
			
		||||
 | 
			
		||||
//go:generate sh -c "wayland-scanner client-header `pkg-config --variable=datarootdir wayland-protocols`/wayland-protocols/staging/security-context/security-context-v1.xml security-context-v1-protocol.h"
 | 
			
		||||
//go:generate sh -c "wayland-scanner private-code `pkg-config --variable=datarootdir wayland-protocols`/wayland-protocols/staging/security-context/security-context-v1.xml security-context-v1-protocol.c"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
#cgo linux pkg-config: --static wayland-client
 | 
			
		||||
#cgo freebsd openbsd LDFLAGS: -lwayland-client
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
@ -23,7 +33,7 @@ static const struct wl_registry_listener registry_listener = {
 | 
			
		||||
  .global_remove = registry_handle_global_remove,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int32_t bind_wayland_fd(char *socket_path, int fd, const char *app_id, const char *instance_id, int sync_fd) {
 | 
			
		||||
static int32_t bind_wayland_fd(char *socket_path, int fd, const char *app_id, const char *instance_id, int sync_fd) {
 | 
			
		||||
  int32_t res = 0; // refer to resErr for meaning
 | 
			
		||||
 | 
			
		||||
  struct wl_display *display;
 | 
			
		||||
@ -86,3 +96,17 @@ out:
 | 
			
		||||
  free((void *)instance_id);
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
import "C"
 | 
			
		||||
import "errors"
 | 
			
		||||
 | 
			
		||||
var resErr = [...]error{
 | 
			
		||||
	0: nil,
 | 
			
		||||
	1: errors.New("wl_display_connect_to_fd() failed"),
 | 
			
		||||
	2: errors.New("wp_security_context_v1 not available"),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bindWaylandFd(socketPath string, fd uintptr, appID, instanceID string, syncFD uintptr) error {
 | 
			
		||||
	res := C.bind_wayland_fd(C.CString(socketPath), C.int(fd), C.CString(appID), C.CString(instanceID), C.int(syncFD))
 | 
			
		||||
	return resErr[int32(res)]
 | 
			
		||||
}
 | 
			
		||||
@ -1,3 +0,0 @@
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
int32_t bind_wayland_fd(char *socket_path, int fd, const char *app_id, const char *instance_id, int sync_fd);
 | 
			
		||||
							
								
								
									
										24
									
								
								wl/wl.go
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								wl/wl.go
									
									
									
									
									
								
							@ -1,24 +0,0 @@
 | 
			
		||||
package wl
 | 
			
		||||
 | 
			
		||||
//go:generate sh -c "wayland-scanner client-header `pkg-config --variable=datarootdir wayland-protocols`/wayland-protocols/staging/security-context/security-context-v1.xml security-context-v1-protocol.h"
 | 
			
		||||
//go:generate sh -c "wayland-scanner private-code `pkg-config --variable=datarootdir wayland-protocols`/wayland-protocols/staging/security-context/security-context-v1.xml security-context-v1-protocol.c"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
#cgo linux pkg-config: --static wayland-client
 | 
			
		||||
#cgo freebsd openbsd LDFLAGS: -lwayland-client
 | 
			
		||||
 | 
			
		||||
#include "wayland-bind.h"
 | 
			
		||||
*/
 | 
			
		||||
import "C"
 | 
			
		||||
import "errors"
 | 
			
		||||
 | 
			
		||||
var resErr = [...]error{
 | 
			
		||||
	0: nil,
 | 
			
		||||
	1: errors.New("wl_display_connect_to_fd() failed"),
 | 
			
		||||
	2: errors.New("wp_security_context_v1 not available"),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bindWaylandFd(socketPath string, fd uintptr, appID, instanceID string, syncFD uintptr) error {
 | 
			
		||||
	res := C.bind_wayland_fd(C.CString(socketPath), C.int(fd), C.CString(appID), C.CString(instanceID), C.int(syncFD))
 | 
			
		||||
	return resErr[int32(res)]
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user