-
-
Notifications
You must be signed in to change notification settings - Fork 372
incusd/instance/lxc: Tweak SELinux category #2653
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: Stéphane Graber <[email protected]>
|
Hi @stgraber, thanks for that! Unfortunately I think this wont work, as
I will apply your change, fix the issues, test it and then paste the result here. |
|
Okay, this stuff is pretty frustrating. We need to be able to run around 20k instances per system without any chance of two getting the same categories. Picking two random numbers doesn't prevent them from being the same nor does it prevent clashes with other instances on the range system. The best would be to be able to encode the instance ID as categories but that needs to support a full 64 bit integer. The alternative would need to be looking at running instances on the system, allocating the next unused category on startup with some kind of global lock going over all the instances, that won't be particularly fast but may be the best bet here. |
|
The following is working for me. It uses 4 cats based on the instance ID. With that it should be safe to run 20.000+ instances. diff '--color=auto' -ur incus-orig/internal/server/instance/drivers/driver_common.go incus/internal/server/instance/drivers/driver_common.go 02:25:46 [16/8029]
--- incus-orig/internal/server/instance/drivers/driver_common.go 2025-11-12 22:46:55.395055647 +0100
+++ incus/internal/server/instance/drivers/driver_common.go 2025-11-13 02:19:17.576129571 +0100
@@ -3,6 +3,8 @@
import (
"cmp"
"context"
+ "crypto/sha256"
+ "encoding/binary"
"errors"
"fmt"
"math"
@@ -1726,3 +1728,46 @@
return nil
}
+
+// selinuxCategory returns the SELinux category suffix.
+func (d *common) selinuxCategory() string {
+ h := sha256.New()
+ binary.Write(h, binary.LittleEndian, int64(d.id))
+ hash := h.Sum(nil)
+
+ // Extract three 32-bit values from hash
+ v1 := binary.LittleEndian.Uint32(hash[0:4])
+ v2 := binary.LittleEndian.Uint32(hash[4:8])
+ v3 := binary.LittleEndian.Uint32(hash[8:12])
+ v4 := binary.LittleEndian.Uint32(hash[12:16])
+
+ // Map to category range [0, 1023]
+ c1 := int(v1 % 1024)
+ c2 := int(v2 % 1024)
+ c3 := int(v3 % 1024)
+ c4 := int(v4 % 1024)
+
+ // Make c2 distinct from c1
+ for c2 == c1 {
+ c2 = (c2 + 1) % 1024
+ }
+
+ // Make c3 distinct from both c1 and c2
+ for c3 == c1 || c3 == c2 {
+ c3 = (c3 + 1) % 1024
+ }
+
+ // Make c4 distinct from c1, c2, and c3
+ for c4 == c1 || c4 == c2 || c4 == c3 {
+ c4 = (c4 + 1) % 1024
+ }
+
+ // Sort for canonical ordering
+ cats := []int{c1, c2, c3, c4}
+ sort.Ints(cats)
+
+ return ":c" + strconv.Itoa(cats[0]) +
+ ",c" + strconv.Itoa(cats[1]) +
+ ",c" + strconv.Itoa(cats[2]) +
+ ",c" + strconv.Itoa(cats[3])
+}
diff '--color=auto' -ur incus-orig/internal/server/instance/drivers/driver_lxc.go incus/internal/server/instance/drivers/driver_lxc.go
--- incus-orig/internal/server/instance/drivers/driver_lxc.go 2025-11-12 22:46:55.398389023 +0100
+++ incus/internal/server/instance/drivers/driver_lxc.go 2025-11-12 22:44:01.919598771 +0100
@@ -1022,7 +1022,7 @@
// Setup SELinux.
if d.state.OS.SELinuxAvailable && d.state.OS.SELinuxContextInstanceLXC != "" {
- err := lxcSetConfigItem(cc, "lxc.selinux.context", fmt.Sprintf("%s:c%d", d.state.OS.SELinuxContextInstanceLXC, d.id))
+ err := lxcSetConfigItem(cc, "lxc.selinux.context", fmt.Sprintf("%s%s", d.state.OS.SELinuxContextInstanceLXC, d.selinuxCategory()))
if err != nil {
return nil, err
} |
A collision risk of > 0% is a security issue for us as users can create and delete instances as many time as they want until they manage to hit what a collision. |
|
So I think we should indeed work with a combination of two categories as that will give us more instances than any system can ever run at any one time. Then we should have a function which will:
We'll have that function take a global lock so we can limit the load it causes and avoid a race at that stage. |
|
If you can give me a hint about how to get that list of instances and how to take the lock I would change the function to do what you suggested. And maybe it would be good if I put that in a seperate PR then? Or can I somehow push into this PR? |
No description provided.