Skip to content

Commit 91d3665

Browse files
committed
Implement personality(2) for no-op personality bits.
Fixes #10756
1 parent 979bbf2 commit 91d3665

File tree

12 files changed

+255
-2
lines changed

12 files changed

+255
-2
lines changed

pkg/abi/linux/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ go_library(
5858
"netlink.go",
5959
"netlink_route.go",
6060
"nf_tables.go",
61+
"personality.go",
6162
"poll.go",
6263
"prctl.go",
6364
"ptrace.go",

pkg/abi/linux/personality.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2024 The gVisor Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package linux
16+
17+
// Personality flags, used by personality(2),
18+
// from include/uapi/linux/personality.h.
19+
const (
20+
SHORT_INODE = 0x1000000
21+
WHOLE_SECONDS = 0x2000000
22+
PER_LINUX = 0x0000
23+
PER_BSD = 0x0006
24+
)
25+
26+
// NOTE: All of the above flags are non-security-sensitive and may be copied
27+
// from parent task to child task. However, this is not the case for all
28+
// personality bits. If adding more, check PER_CLEAR_ON_SETID and ensure that
29+
// these are cleared on suid/sgid execs.

pkg/sentry/kernel/kernel.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,7 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
11571157
InitialCgroups: args.InitialCgroups,
11581158
UserCounters: k.GetUserCounters(args.Credentials.RealKUID),
11591159
Origin: args.Origin,
1160+
Personality: linux.PER_LINUX,
11601161
// A task with no parent starts out with no session keyring.
11611162
SessionKeyring: nil,
11621163
}

pkg/sentry/kernel/task.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,9 @@ type Task struct {
608608
// +checklocks:mu
609609
sessionKeyring *auth.Key
610610

611+
// personality is the task's personality(2) bits.
612+
personality atomicbitops.Uint32
613+
611614
// Origin is the origin of the task.
612615
Origin TaskOrigin
613616
}
@@ -869,3 +872,14 @@ func (t *Task) ResetKcov() {
869872
t.kcov = nil
870873
}
871874
}
875+
876+
// Personality returns the task's personality.
877+
func (t *Task) Personality() uint32 {
878+
return t.personality.Load()
879+
}
880+
881+
// SetPersonality sets the task's personality.
882+
// It returns the task's former personality.
883+
func (t *Task) SetPersonality(personality uint32) uint32 {
884+
return t.personality.Swap(personality)
885+
}

pkg/sentry/kernel/task_clone.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ func (t *Task) Clone(args *linux.CloneArgs) (ThreadID, *SyscallControl, error) {
265265
ContainerID: t.ContainerID(),
266266
UserCounters: uc,
267267
SessionKeyring: sessionKeyring,
268+
Personality: t.personality.Load(),
268269
Origin: t.Origin,
269270
}
270271
if args.Flags&linux.CLONE_THREAD == 0 {

pkg/sentry/kernel/task_start.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ type TaskConfig struct {
104104
// It may be nil.
105105
SessionKeyring *auth.Key
106106

107+
// Personality is the personality of the parent task.
108+
Personality uint32
109+
107110
Origin TaskOrigin
108111
}
109112

@@ -174,6 +177,7 @@ func (ts *TaskSet) newTask(ctx context.Context, cfg *TaskConfig) (*Task, error)
174177
cgroups: make(map[Cgroup]struct{}),
175178
userCounters: cfg.UserCounters,
176179
sessionKeyring: cfg.SessionKeyring,
180+
personality: atomicbitops.FromUint32(cfg.Personality),
177181
Origin: cfg.Origin,
178182
}
179183
t.netns = cfg.NetworkNamespace

pkg/sentry/syscalls/linux/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ go_library(
3333
"sys_mount.go",
3434
"sys_mq.go",
3535
"sys_msgqueue.go",
36+
"sys_personality.go",
3637
"sys_pipe.go",
3738
"sys_poll.go",
3839
"sys_prctl.go",

pkg/sentry/syscalls/linux/linux64.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ var AMD64 = &kernel.SyscallTable{
187187
132: syscalls.Supported("utime", Utime),
188188
133: syscalls.Supported("mknod", Mknod),
189189
134: syscalls.Error("uselib", linuxerr.ENOSYS, "Obsolete", nil),
190-
135: syscalls.ErrorWithEvent("personality", linuxerr.EINVAL, "Unable to change personality.", nil),
190+
135: syscalls.PartiallySupported("personality", Personality, "Only setting no-op personality bits and retrieving them are supported.", nil),
191191
136: syscalls.ErrorWithEvent("ustat", linuxerr.ENOSYS, "Needs filesystem support.", nil),
192192
137: syscalls.Supported("statfs", Statfs),
193193
138: syscalls.Supported("fstatfs", Fstatfs),
@@ -523,7 +523,7 @@ var ARM64 = &kernel.SyscallTable{
523523
89: syscalls.CapError("acct", linux.CAP_SYS_PACCT, "", nil),
524524
90: syscalls.Supported("capget", Capget),
525525
91: syscalls.Supported("capset", Capset),
526-
92: syscalls.ErrorWithEvent("personality", linuxerr.EINVAL, "Unable to change personality.", nil),
526+
92: syscalls.PartiallySupported("personality", Personality, "Only setting no-op personality bits and retrieving them are supported.", nil),
527527
93: syscalls.Supported("exit", Exit),
528528
94: syscalls.Supported("exit_group", ExitGroup),
529529
95: syscalls.Supported("waitid", Waitid),
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2024 The gVisor Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package linux
16+
17+
import (
18+
"gvisor.dev/gvisor/pkg/abi/linux"
19+
"gvisor.dev/gvisor/pkg/errors/linuxerr"
20+
"gvisor.dev/gvisor/pkg/sentry/arch"
21+
"gvisor.dev/gvisor/pkg/sentry/kernel"
22+
)
23+
24+
const (
25+
// getPersonality may be passed to `personality(2)` to get the current
26+
// personality bits without modifying them.
27+
getPersonality = 0xffffffff
28+
)
29+
30+
// Personality implements Linux syscall personality(2).
31+
func Personality(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
32+
// allowedPersonalityBits are the personality bits that are allowed to be set.
33+
const allowedPersonalityBits = linux.PER_LINUX | linux.PER_BSD | linux.SHORT_INODE | linux.WHOLE_SECONDS
34+
35+
personality := args[0].Uint()
36+
if personality == getPersonality {
37+
return uintptr(t.Personality()), nil, nil
38+
}
39+
if personality&allowedPersonalityBits != personality {
40+
return 0, nil, linuxerr.EINVAL
41+
}
42+
return uintptr(t.SetPersonality(personality)), nil, nil
43+
}

test/syscalls/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,10 @@ syscall_test(
479479
test = "//test/syscalls/linux:pause_test",
480480
)
481481

482+
syscall_test(
483+
test = "//test/syscalls/linux:personality_test",
484+
)
485+
482486
syscall_test(
483487
size = "medium",
484488
add_hostinet = True,

0 commit comments

Comments
 (0)