mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Implement ipc.Object.Set and use it in ipc mechanisms.
Set provides functionality of {sem,shm,msg}ctl(IPC_SET).
This commit is contained in:
@@ -19,6 +19,8 @@ package ipc
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
)
|
||||
@@ -113,3 +115,36 @@ func (o *Object) CheckPermissions(creds *auth.Credentials, req fs.PermMask) bool
|
||||
}
|
||||
return creds.HasCapabilityIn(linux.CAP_IPC_OWNER, o.UserNS)
|
||||
}
|
||||
|
||||
// Set modifies attributes for an IPC object. See *ctl(IPC_SET).
|
||||
//
|
||||
// Precondition: Mechanism.mu must be held.
|
||||
func (o *Object) Set(ctx context.Context, perm *linux.IPCPerm) error {
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
uid := creds.UserNamespace.MapToKUID(auth.UID(perm.UID))
|
||||
gid := creds.UserNamespace.MapToKGID(auth.GID(perm.GID))
|
||||
if !uid.Ok() || !gid.Ok() {
|
||||
// The man pages don't specify an errno for invalid uid/gid, but EINVAL
|
||||
// is generally used for invalid arguments.
|
||||
return linuxerr.EINVAL
|
||||
}
|
||||
|
||||
if !o.CheckOwnership(creds) {
|
||||
// "The argument cmd has the value IPC_SET or IPC_RMID, but the
|
||||
// effective user ID of the calling process is not the creator (as
|
||||
// found in msg_perm.cuid) or the owner (as found in msg_perm.uid)
|
||||
// of the message queue, and the caller is not privileged (Linux:
|
||||
// does not have the CAP_SYS_ADMIN capability)."
|
||||
return linuxerr.EPERM
|
||||
}
|
||||
|
||||
// User may only modify the lower 9 bits of the mode. All the other bits are
|
||||
// always 0 for the underlying inode.
|
||||
mode := linux.FileMode(perm.Mode & 0x1ff)
|
||||
|
||||
o.Perms = fs.FilePermsFromMode(mode)
|
||||
o.Owner.UID = uid
|
||||
o.Owner.GID = gid
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -337,19 +337,15 @@ func (s *Set) Size() int {
|
||||
return len(s.sems)
|
||||
}
|
||||
|
||||
// Change changes some fields from the set atomically.
|
||||
func (s *Set) Change(ctx context.Context, creds *auth.Credentials, owner fs.FileOwner, perms fs.FilePermissions) error {
|
||||
// Set modifies attributes for a semaphore set. See semctl(IPC_SET).
|
||||
func (s *Set) Set(ctx context.Context, ds *linux.SemidDS) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
// "The effective UID of the calling process must match the owner or creator
|
||||
// of the semaphore set, or the caller must be privileged."
|
||||
if !s.obj.CheckOwnership(creds) {
|
||||
return linuxerr.EACCES
|
||||
if err := s.obj.Set(ctx, &ds.SemPerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.obj.Owner = owner
|
||||
s.obj.Perms = perms
|
||||
s.changeTime = ktime.NowFromContext(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -619,25 +619,10 @@ func (s *Shm) Set(ctx context.Context, ds *linux.ShmidDS) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
if !s.obj.CheckOwnership(creds) {
|
||||
return linuxerr.EPERM
|
||||
if err := s.obj.Set(ctx, &ds.ShmPerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
uid := creds.UserNamespace.MapToKUID(auth.UID(ds.ShmPerm.UID))
|
||||
gid := creds.UserNamespace.MapToKGID(auth.GID(ds.ShmPerm.GID))
|
||||
if !uid.Ok() || !gid.Ok() {
|
||||
return linuxerr.EINVAL
|
||||
}
|
||||
|
||||
// User may only modify the lower 9 bits of the mode. All the other bits are
|
||||
// always 0 for the underlying inode.
|
||||
mode := linux.FileMode(ds.ShmPerm.Mode & 0x1ff)
|
||||
s.obj.Perms = fs.FilePermsFromMode(mode)
|
||||
|
||||
s.obj.Owner.UID = uid
|
||||
s.obj.Owner.GID = gid
|
||||
|
||||
s.changeTime = ktime.NowFromContext(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/hostarch"
|
||||
"gvisor.dev/gvisor/pkg/marshal/primitive"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/ipc"
|
||||
@@ -166,8 +165,7 @@ func Semctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
perms := fs.FilePermsFromMode(linux.FileMode(s.SemPerm.Mode & 0777))
|
||||
return 0, nil, ipcSet(t, id, auth.UID(s.SemPerm.UID), auth.GID(s.SemPerm.GID), perms)
|
||||
return 0, nil, ipcSet(t, id, &s)
|
||||
|
||||
case linux.GETPID:
|
||||
v, err := getPID(t, id, num)
|
||||
@@ -243,24 +241,13 @@ func remove(t *kernel.Task, id ipc.ID) error {
|
||||
return r.Remove(id, creds)
|
||||
}
|
||||
|
||||
func ipcSet(t *kernel.Task, id ipc.ID, uid auth.UID, gid auth.GID, perms fs.FilePermissions) error {
|
||||
func ipcSet(t *kernel.Task, id ipc.ID, ds *linux.SemidDS) error {
|
||||
r := t.IPCNamespace().SemaphoreRegistry()
|
||||
set := r.FindByID(id)
|
||||
if set == nil {
|
||||
return linuxerr.EINVAL
|
||||
}
|
||||
|
||||
creds := auth.CredentialsFromContext(t)
|
||||
kuid := creds.UserNamespace.MapToKUID(uid)
|
||||
if !kuid.Ok() {
|
||||
return linuxerr.EINVAL
|
||||
}
|
||||
kgid := creds.UserNamespace.MapToKGID(gid)
|
||||
if !kgid.Ok() {
|
||||
return linuxerr.EINVAL
|
||||
}
|
||||
owner := fs.FileOwner{UID: kuid, GID: kgid}
|
||||
return set.Change(t, creds, owner, perms)
|
||||
return set.Set(t, ds)
|
||||
}
|
||||
|
||||
func ipcStat(t *kernel.Task, id ipc.ID) (*linux.SemidDS, error) {
|
||||
|
||||
Reference in New Issue
Block a user