blob: b09feda2aadc4a5dc8829d88f5e1b14fe296b3e5 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package hwsec
import (
"context"
"fmt"
"math/rand"
"time"
"chromiumos/tast/errors"
hwseclocal "chromiumos/tast/local/hwsec"
"chromiumos/tast/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: ChapsCloseAllSessions,
Desc: "Verifies that the behaviour of C_CloseAllSessions() in libchaps is correct",
Contacts: []string{
"cros-hwsec@chromium.org",
"zuan@chromium.org",
},
SoftwareDeps: []string{"tpm"},
Attr: []string{"group:mainline"},
Timeout: 1 * time.Minute,
})
}
const (
delayForLoopRoutine = 700 * time.Millisecond
)
// ChapsCloseAllSessions verifies the behaviour of C_CloseAllSessions() in libchaps is correct.
func ChapsCloseAllSessions(ctx context.Context, s *testing.State) {
// This test works by running --check_close_all_sessions and --use_sessions_loop part of p11_replay concurrently.
// --use_sessions_loop will create a session for itself, then notify through the IPC file that it's got a working session, then it'll continuously verify that the session is still working, until it've received communication from the IPC file that we're done, then it'll exit.
// --check_close_all_sessions will wait for --use_sessions_loop to be ready, as in, --use_sessions_loop's session is created. --check_close_all_sessions waits for this even through polling the IPC file. After that, it'll create a session (for itself, different from the one created by --use_sessions_loop), call C_CloseAllSessions() to verify that it is closed, then signal to --use_sessions_loop through IPC file that it's done.
// In summary, what is done is checking that C_CloseAllSessions() doesn't affect other users of chaps PKCS#11 API, while C_CloseAllSessions() works.
cmdRunner := hwseclocal.NewCmdRunner()
// Create the file for IPC between --check_close_all_sessions and --use_sessions_loop.
seededRand := rand.New(rand.NewSource(time.Now().UnixNano()))
ipcFile := fmt.Sprintf("/tmp/chaps_close_all_sessions_%d_%d", seededRand.Uint32(), seededRand.Uint32())
defer func() {
// We cleanup anyway, but if it failed and cleanup is needed, then we log the warning.
if _, err := cmdRunner.Run(ctx, "rm", "-f", ipcFile); err != nil {
s.Log("Failed to remove the IPC file: ", err)
}
}()
checkErr := make(chan error)
checkRoutine := func() {
if _, err := cmdRunner.Run(ctx, "p11_replay", "--replay_close_all_sessions", "--check_close_all_sessions", "--ipc_file="+ipcFile); err != nil {
checkErr <- errors.Wrap(err, "failed to run p11_replay --replay_close_all_sessions --check_close_all_sessions")
} else {
checkErr <- nil
}
}
go checkRoutine()
if _, err := cmdRunner.Run(ctx, "p11_replay", "--replay_close_all_sessions", "--use_sessions_loop", "--ipc_file="+ipcFile); err != nil {
s.Error("Loop routine failed: ", err)
}
if err := <-checkErr; err != nil {
s.Error("Check routine failed: ", err)
}
}