// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package seccomp

/*
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <errno.h>
#include <stddef.h>
#include <unistd.h>
#include <stdint.h>

// A few definitions copied from linux/filter.h and linux/seccomp.h,
// which might not be available on all systems.

struct sock_filter {
    uint16_t code;
    uint8_t jt;
    uint8_t jf;
    uint32_t k;
};

struct sock_fprog {
    unsigned short len;
    struct sock_filter *filter;
};

#define BPF_LD	0x00
#define BPF_W	0x00
#define BPF_ABS	0x20
#define BPF_JMP	0x05
#define BPF_JEQ	0x10
#define BPF_K	0x00
#define BPF_RET	0x06

#define BPF_STMT(code, k) { (unsigned short)(code), 0, 0, k }
#define BPF_JUMP(code, k, jt, jf) { (unsigned short)(code), jt, jf, k }

struct seccomp_data {
	int nr;
	uint32_t arch;
	uint64_t instruction_pointer;
	uint64_t args[6];
};

#define SECCOMP_RET_ERRNO 0x00050000U
#define SECCOMP_RET_ALLOW 0x7fff0000U
#define SECCOMP_SET_MODE_FILTER 1

int disable_getrandom() {
    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
        return 1;
    }
    struct sock_filter filter[] = {
        BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_getrandom, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | ENOSYS),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
    };
    struct sock_fprog prog = {
        .len = sizeof(filter) / sizeof((filter)[0]),
        .filter = filter,
    };
    if (syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &prog)) {
        return 2;
    }
    return 0;
}
*/
import "C"
import "fmt"

// DisableGetrandom makes future calls to getrandom(2) fail with ENOSYS. It
// applies only to the current thread and to any programs executed from it.
// Callers should use [runtime.LockOSThread] in a dedicated goroutine.
func DisableGetrandom() error {
	if errno := C.disable_getrandom(); errno != 0 {
		return fmt.Errorf("failed to disable getrandom: %v", errno)
	}
	return nil
}
