Implement SEM_STAT_ANY cmd of semctl.
PiperOrigin-RevId: 359591577
This commit is contained in:
parent
56053f084f
commit
e50ee26207
|
@ -381,15 +381,24 @@ func (s *Set) Change(ctx context.Context, creds *auth.Credentials, owner fs.File
|
|||
|
||||
// GetStat extracts semid_ds information from the set.
|
||||
func (s *Set) GetStat(creds *auth.Credentials) (*linux.SemidDS, error) {
|
||||
// "The calling process must have read permission on the semaphore set."
|
||||
return s.semStat(creds, fs.PermMask{Read: true})
|
||||
}
|
||||
|
||||
// GetStatAny extracts semid_ds information from the set without requiring read access.
|
||||
func (s *Set) GetStatAny(creds *auth.Credentials) (*linux.SemidDS, error) {
|
||||
return s.semStat(creds, fs.PermMask{})
|
||||
}
|
||||
|
||||
func (s *Set) semStat(creds *auth.Credentials, permMask fs.PermMask) (*linux.SemidDS, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
// "The calling process must have read permission on the semaphore set."
|
||||
if !s.checkPerms(creds, fs.PermMask{Read: true}) {
|
||||
if !s.checkPerms(creds, permMask) {
|
||||
return nil, syserror.EACCES
|
||||
}
|
||||
|
||||
ds := &linux.SemidDS{
|
||||
return &linux.SemidDS{
|
||||
SemPerm: linux.IPCPerm{
|
||||
Key: uint32(s.key),
|
||||
UID: uint32(creds.UserNamespace.MapFromKUID(s.owner.UID)),
|
||||
|
@ -402,8 +411,7 @@ func (s *Set) GetStat(creds *auth.Credentials) (*linux.SemidDS, error) {
|
|||
SemOTime: s.opTime.TimeT(),
|
||||
SemCTime: s.changeTime.TimeT(),
|
||||
SemNSems: uint64(s.Size()),
|
||||
}
|
||||
return ds, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SetVal overrides a semaphore value, waking up waiters as needed.
|
||||
|
|
|
@ -118,7 +118,7 @@ var AMD64 = &kernel.SyscallTable{
|
|||
63: syscalls.Supported("uname", Uname),
|
||||
64: syscalls.Supported("semget", Semget),
|
||||
65: syscalls.PartiallySupported("semop", Semop, "Option SEM_UNDO not supported.", nil),
|
||||
66: syscalls.PartiallySupported("semctl", Semctl, "Options SEM_STAT_ANY not supported.", nil),
|
||||
66: syscalls.Supported("semctl", Semctl),
|
||||
67: syscalls.Supported("shmdt", Shmdt),
|
||||
68: syscalls.ErrorWithEvent("msgget", syserror.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921)
|
||||
69: syscalls.ErrorWithEvent("msgsnd", syserror.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921)
|
||||
|
@ -619,7 +619,7 @@ var ARM64 = &kernel.SyscallTable{
|
|||
188: syscalls.ErrorWithEvent("msgrcv", syserror.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921)
|
||||
189: syscalls.ErrorWithEvent("msgsnd", syserror.ENOSYS, "", []string{"gvisor.dev/issue/135"}), // TODO(b/29354921)
|
||||
190: syscalls.Supported("semget", Semget),
|
||||
191: syscalls.PartiallySupported("semctl", Semctl, "Options SEM_STAT_ANY not supported.", nil),
|
||||
191: syscalls.Supported("semctl", Semctl),
|
||||
192: syscalls.Supported("semtimedop", Semtimedop),
|
||||
193: syscalls.PartiallySupported("semop", Semop, "Option SEM_UNDO not supported.", nil),
|
||||
194: syscalls.PartiallySupported("shmget", Shmget, "Option SHM_HUGETLB is not supported.", nil),
|
||||
|
|
|
@ -220,8 +220,16 @@ func Semctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
|
|||
return uintptr(semid), nil, err
|
||||
|
||||
case linux.SEM_STAT_ANY:
|
||||
t.Kernel().EmitUnimplementedEvent(t)
|
||||
fallthrough
|
||||
arg := args[3].Pointer()
|
||||
// id is an index in SEM_STAT.
|
||||
semid, ds, err := semStatAny(t, id)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if _, err := ds.CopyOut(t, arg); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
return uintptr(semid), nil, err
|
||||
|
||||
default:
|
||||
return 0, nil, syserror.EINVAL
|
||||
|
@ -272,7 +280,23 @@ func semStat(t *kernel.Task, index int32) (int32, *linux.SemidDS, error) {
|
|||
}
|
||||
creds := auth.CredentialsFromContext(t)
|
||||
ds, err := set.GetStat(creds)
|
||||
return set.ID, ds, err
|
||||
if err != nil {
|
||||
return 0, ds, err
|
||||
}
|
||||
return set.ID, ds, nil
|
||||
}
|
||||
|
||||
func semStatAny(t *kernel.Task, index int32) (int32, *linux.SemidDS, error) {
|
||||
set := t.IPCNamespace().SemaphoreRegistry().FindByIndex(index)
|
||||
if set == nil {
|
||||
return 0, nil, syserror.EINVAL
|
||||
}
|
||||
creds := auth.CredentialsFromContext(t)
|
||||
ds, err := set.GetStatAny(creds)
|
||||
if err != nil {
|
||||
return 0, ds, err
|
||||
}
|
||||
return set.ID, ds, nil
|
||||
}
|
||||
|
||||
func setVal(t *kernel.Task, id int32, num int32, val int16) error {
|
||||
|
|
|
@ -68,6 +68,15 @@ class AutoSem {
|
|||
int id_ = -1;
|
||||
};
|
||||
|
||||
bool operator==(struct semid_ds const& a, struct semid_ds const& b) {
|
||||
return a.sem_perm.__key == b.sem_perm.__key &&
|
||||
a.sem_perm.uid == b.sem_perm.uid && a.sem_perm.gid == b.sem_perm.gid &&
|
||||
a.sem_perm.cuid == b.sem_perm.cuid &&
|
||||
a.sem_perm.cgid == b.sem_perm.cgid &&
|
||||
a.sem_perm.mode == b.sem_perm.mode && a.sem_otime == b.sem_otime &&
|
||||
a.sem_ctime == b.sem_ctime && a.sem_nsems == b.sem_nsems;
|
||||
}
|
||||
|
||||
TEST(SemaphoreTest, SemGet) {
|
||||
// Test creation and lookup.
|
||||
AutoSem sem(semget(1, 10, IPC_CREAT));
|
||||
|
@ -843,6 +852,10 @@ TEST(SemaphoreTest, SemopGetncntOnSignal_NoRandomSave) {
|
|||
EXPECT_EQ(semctl(sem.get(), 0, GETNCNT), 0);
|
||||
}
|
||||
|
||||
#ifndef SEM_STAT_ANY
|
||||
#define SEM_STAT_ANY 20
|
||||
#endif // SEM_STAT_ANY
|
||||
|
||||
TEST(SemaphoreTest, IpcInfo) {
|
||||
constexpr int kLoops = 5;
|
||||
std::set<int> sem_ids;
|
||||
|
@ -868,15 +881,7 @@ TEST(SemaphoreTest, IpcInfo) {
|
|||
if (sem_ids.find(sem_id) != sem_ids.end()) {
|
||||
struct semid_ds ipc_stat_ds;
|
||||
ASSERT_THAT(semctl(sem_id, 0, IPC_STAT, &ipc_stat_ds), SyscallSucceeds());
|
||||
EXPECT_EQ(ds.sem_perm.__key, ipc_stat_ds.sem_perm.__key);
|
||||
EXPECT_EQ(ds.sem_perm.uid, ipc_stat_ds.sem_perm.uid);
|
||||
EXPECT_EQ(ds.sem_perm.gid, ipc_stat_ds.sem_perm.gid);
|
||||
EXPECT_EQ(ds.sem_perm.cuid, ipc_stat_ds.sem_perm.cuid);
|
||||
EXPECT_EQ(ds.sem_perm.cgid, ipc_stat_ds.sem_perm.cgid);
|
||||
EXPECT_EQ(ds.sem_perm.mode, ipc_stat_ds.sem_perm.mode);
|
||||
EXPECT_EQ(ds.sem_otime, ipc_stat_ds.sem_otime);
|
||||
EXPECT_EQ(ds.sem_ctime, ipc_stat_ds.sem_ctime);
|
||||
EXPECT_EQ(ds.sem_nsems, ipc_stat_ds.sem_nsems);
|
||||
EXPECT_TRUE(ds == ipc_stat_ds);
|
||||
|
||||
// Remove the semaphore set's read permission.
|
||||
struct semid_ds ipc_set_ds;
|
||||
|
@ -884,9 +889,21 @@ TEST(SemaphoreTest, IpcInfo) {
|
|||
ipc_set_ds.sem_perm.gid = getgid();
|
||||
// Keep the semaphore set's write permission so that it could be removed.
|
||||
ipc_set_ds.sem_perm.mode = 0200;
|
||||
// IPC_SET command here updates sem_ctime member of the sem.
|
||||
ASSERT_THAT(semctl(sem_id, 0, IPC_SET, &ipc_set_ds), SyscallSucceeds());
|
||||
ASSERT_THAT(semctl(i, 0, SEM_STAT, &ds), SyscallFailsWithErrno(EACCES));
|
||||
|
||||
int val = semctl(i, 0, SEM_STAT_ANY, &ds);
|
||||
if (val == -1) {
|
||||
// Only if the kernel doesn't support the command SEM_STAT_ANY.
|
||||
EXPECT_TRUE(errno == EINVAL || errno == EFAULT);
|
||||
} else {
|
||||
EXPECT_EQ(sem_id, val);
|
||||
EXPECT_LE(ipc_stat_ds.sem_ctime, ds.sem_ctime);
|
||||
ipc_stat_ds.sem_ctime = 0;
|
||||
ipc_stat_ds.sem_perm.mode = 0200;
|
||||
ds.sem_ctime = 0;
|
||||
EXPECT_TRUE(ipc_stat_ds == ds);
|
||||
}
|
||||
sem_ids_before_max_index.insert(sem_id);
|
||||
}
|
||||
}
|
||||
|
@ -946,15 +963,7 @@ TEST(SemaphoreTest, SemInfo) {
|
|||
if (sem_ids.find(sem_id) != sem_ids.end()) {
|
||||
struct semid_ds ipc_stat_ds;
|
||||
ASSERT_THAT(semctl(sem_id, 0, IPC_STAT, &ipc_stat_ds), SyscallSucceeds());
|
||||
EXPECT_EQ(ds.sem_perm.__key, ipc_stat_ds.sem_perm.__key);
|
||||
EXPECT_EQ(ds.sem_perm.uid, ipc_stat_ds.sem_perm.uid);
|
||||
EXPECT_EQ(ds.sem_perm.gid, ipc_stat_ds.sem_perm.gid);
|
||||
EXPECT_EQ(ds.sem_perm.cuid, ipc_stat_ds.sem_perm.cuid);
|
||||
EXPECT_EQ(ds.sem_perm.cgid, ipc_stat_ds.sem_perm.cgid);
|
||||
EXPECT_EQ(ds.sem_perm.mode, ipc_stat_ds.sem_perm.mode);
|
||||
EXPECT_EQ(ds.sem_otime, ipc_stat_ds.sem_otime);
|
||||
EXPECT_EQ(ds.sem_ctime, ipc_stat_ds.sem_ctime);
|
||||
EXPECT_EQ(ds.sem_nsems, ipc_stat_ds.sem_nsems);
|
||||
EXPECT_TRUE(ds == ipc_stat_ds);
|
||||
|
||||
// Remove the semaphore set's read permission.
|
||||
struct semid_ds ipc_set_ds;
|
||||
|
@ -962,9 +971,22 @@ TEST(SemaphoreTest, SemInfo) {
|
|||
ipc_set_ds.sem_perm.gid = getgid();
|
||||
// Keep the semaphore set's write permission so that it could be removed.
|
||||
ipc_set_ds.sem_perm.mode = 0200;
|
||||
// IPC_SET command here updates sem_ctime member of the sem.
|
||||
ASSERT_THAT(semctl(sem_id, 0, IPC_SET, &ipc_set_ds), SyscallSucceeds());
|
||||
ASSERT_THAT(semctl(i, 0, SEM_STAT, &ds), SyscallFailsWithErrno(EACCES));
|
||||
int val = semctl(i, 0, SEM_STAT_ANY, &ds);
|
||||
|
||||
if (val == -1) {
|
||||
// Only if the kernel doesn't support the command SEM_STAT_ANY.
|
||||
EXPECT_TRUE(errno == EINVAL || errno == EFAULT);
|
||||
} else {
|
||||
EXPECT_EQ(val, sem_id);
|
||||
EXPECT_LE(ipc_stat_ds.sem_ctime, ds.sem_ctime);
|
||||
ipc_stat_ds.sem_ctime = 0;
|
||||
ipc_stat_ds.sem_perm.mode = 0200;
|
||||
ds.sem_ctime = 0;
|
||||
EXPECT_TRUE(ipc_stat_ds == ds);
|
||||
}
|
||||
sem_ids_before_max_index.insert(sem_id);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue