สิ่งที่คุณมีตรงนี้คือกรณีการใช้งานseccompอย่างแน่นอน
ด้วย seccomp คุณสามารถกรอง syscalls ได้หลายวิธี สิ่งที่คุณต้องการจะทำอย่างไรในสถานการณ์เช่นนี้เป็นขวาหลังจากที่fork()
, การติดตั้งseccomp
ตัวกรองที่ไม่อนุญาตให้ใช้open(2)
, openat(2)
, socket(2)
(และอื่น ๆ ) ในการทำสิ่งนี้ให้สำเร็จคุณสามารถทำสิ่งต่อไปนี้:
- ขั้นแรกให้สร้างบริบท seccomp ใช้กับการทำงานเริ่มต้นของ
seccomp_init(3)
SCMP_ACT_ALLOW
- จากนั้นเพิ่มกฎในบริบทที่ใช้
seccomp_rule_add(3)
สำหรับ syscall แต่ละรายการที่คุณต้องการปฏิเสธ คุณสามารถใช้SCMP_ACT_KILL
เพื่อฆ่ากระบวนการหากพยายาม syscall SCMP_ACT_ERRNO(val)
เพื่อทำให้ syscall ล้มเหลวในการส่งคืนerrno
ค่าที่ระบุหรือaction
ค่าอื่น ๆ ที่กำหนดไว้ในหน้าคู่มือ
- โหลดบริบทที่ใช้
seccomp_load(3)
เพื่อให้มีประสิทธิภาพ
ก่อนดำเนินการต่อโปรดทราบว่าวิธีการที่บัญชีดำแบบนี้โดยทั่วไปแล้วจะอ่อนแอกว่าวิธีที่อยู่ในบัญชีปลอดภัย จะอนุญาตให้ syscall ใด ๆ ที่ไม่ได้รับอนุญาตอย่างชัดเจนและอาจส่งผลให้ตัวกรองผ่านได้ หากคุณเชื่อว่ากระบวนการลูกที่คุณต้องการเรียกใช้อาจพยายามหลีกเลี่ยงตัวกรองโดยมีเจตนาร้ายหรือถ้าคุณรู้อยู่แล้วว่าเด็ก ๆ ต้องการตึกระฟ้าแบบใดวิธีการที่ปลอดภัยจะดีกว่าและคุณควรทำสิ่งตรงกันข้ามกับด้านบน: สร้างตัวกรองที่มีการดำเนินการเริ่มต้นของSCMP_ACT_KILL
และช่วยให้ syscalls SCMP_ACT_ALLOW
จำเป็นด้วย ในแง่ของรหัสความแตกต่างนั้นน้อยที่สุด (รายการที่อนุญาตอาจจะยาวกว่า แต่ขั้นตอนเหมือนกัน)
นี่คือตัวอย่างของข้างต้น (ฉันกำลังทำexit(-1)
ในกรณีของข้อผิดพลาดเพียงเพื่อความเรียบง่าย):
#include <stdlib.h>
#include <seccomp.h>
static void secure(void) {
int err;
scmp_filter_ctx ctx;
int blacklist[] = {
SCMP_SYS(open),
SCMP_SYS(openat),
SCMP_SYS(creat),
SCMP_SYS(socket),
SCMP_SYS(open_by_handle_at),
// ... possibly more ...
};
// Create a new seccomp context, allowing every syscall by default.
ctx = seccomp_init(SCMP_ACT_ALLOW);
if (ctx == NULL)
exit(-1);
/* Now add a filter for each syscall that you want to disallow.
In this case, we'll use SCMP_ACT_KILL to kill the process if it
attempts to execute the specified syscall. */
for (unsigned i = 0; i < sizeof(blacklist) / sizeof(blacklist[0]); i++) {
err = seccomp_rule_add(ctx, SCMP_ACT_KILL, blacklist[i], 0);
if (err)
exit(-1);
}
// Load the context making it effective.
err = seccomp_load(ctx);
if (err)
exit(-1);
}
ตอนนี้ในโปรแกรมของคุณคุณสามารถเรียกใช้ฟังก์ชันข้างต้นเพื่อใช้ตัวกรอง seccomp หลังจากfork()
นั้นเช่นนี้
child_pid = fork();
if (child_pid == -1)
exit(-1);
if (child_pid == 0) {
secure();
// Child code here...
exit(0);
} else {
// Parent code here...
}
หมายเหตุสำคัญบางประการเกี่ยวกับ seccomp:
- ตัวกรอง seccomp ที่ใช้ครั้งเดียวจะไม่สามารถลบหรือแก้ไขได้โดยกระบวนการ
- หาก
fork(2)
หรือclone(2)
ได้รับอนุญาตจากตัวกรองกระบวนการลูกใด ๆ จะถูก จำกัด โดยตัวกรองเดียวกัน
- หากได้รับอนุญาตการกรองที่มีอยู่จะถูกเก็บไว้ข้ามเรียกร้องให้
execve(2)
execve(2)
- หาก
prctl(2)
อนุญาตให้ syscall กระบวนการสามารถใช้ตัวกรองเพิ่มเติมได้