diff -r 000000000000 -r bde4ae8d615e os/persistentdata/persistentstorage/sql/TEST/t_sqlbadclient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/persistentdata/persistentstorage/sql/TEST/t_sqlbadclient.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,677 @@ +// Copyright (c) 2006-2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include +#include +#include +#include +#include "SqlUtil.h" +#include "SqlSrvStartup.h" //KSqlMajorVer, KSqlMinorVer, KSqlBuildVer + +/////////////////////////////////////////////////////////////////////////////////////// + +static RFs TheFs; +RTest TheTest(_L("t_sqlbadclient test")); +_LIT(KTestDir, "c:\\test\\"); +_LIT(KTestDbName1, "c:\\test\\t_sqlbadclient.db"); +_LIT(KTestDbName2, "c:[1111D1C1]t_sqlbadclient.db"); + +#if defined __WINS__ || defined __WINSCW__ +const TInt KTestIterCount = 5000; +#else +const TInt KTestIterCount = 4000; +#endif +const TInt KMaxDesArgLen = 1000; +enum TArgType + { + EIntArgType, + ETextArgType, + EBinArgType, + ELastArgType + }; + +////////////////////////////////////////////////////////////////////////////////////// + +//If the SQL server crashes and the test receives KErrServerTerminated error, then the +//next set will contain the last: +// - iteration number; +// - handle type; +// - function code; +// - handle; +// - IPC arguments values; +struct TThreadData + { + TInt iIteration; + TSqlSrvHandleType iHandleType; + TInt iFunction; + TInt iHandle; + TArgType iArgType[KMaxMessageArguments]; + TInt iIntArg[KMaxMessageArguments]; + TBuf iTextArg[KMaxMessageArguments]; + TBuf8 iBinArg[KMaxMessageArguments]; + TInt64 iSeed; + }; +////////////////////////////////////////////////////////////////////////////////////// + +_LIT(KPanicCategory, "SrvTerm"); +_LIT(KPanicCategory2, "InvArg"); +const TInt KPanicCode = 1111; +const TInt KPanicCode2 = 2222; + +/////////////////////////////////////////////////////////////////////////////////////// + +//Deletes all created test files. +void DeleteTestFiles() + { + RSqlDatabase::Delete(KTestDbName1); + } + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +//Test macros and functions +void Check1(TInt aValue, TInt aLine, TBool aPrintThreadName = EFalse) + { + if(!aValue) + { + DeleteTestFiles(); + if(aPrintThreadName) + { + RThread th; + TName name = th.Name(); + RDebug::Print(_L("*** Thread %S, Line %d\r\n"), &name, aLine); + } + else + { + RDebug::Print(_L("*** Line %d\r\n"), aLine); + } + TheTest(EFalse, aLine); + } + } +void Check2(TInt aValue, TInt aExpected, TInt aLine, TBool aPrintThreadName = EFalse) + { + if(aValue != aExpected) + { + DeleteTestFiles(); + if(aPrintThreadName) + { + RThread th; + TName name = th.Name(); + RDebug::Print(_L("*** Thread %S, Line %d Expected error: %d, got: %d\r\n"), &name, aLine, aExpected, aValue); + } + else + { + RDebug::Print(_L("*** Line %d, Expected error: %d, got: %d\r\n"), aLine, aExpected, aValue); + } + TheTest(EFalse, aLine); + } + } +#define TEST(arg) ::Check1((arg), __LINE__) +#define TEST2(aValue, aExpected) ::Check2(aValue, aExpected, __LINE__) +#define TTEST(arg) ::Check1((arg), __LINE__, ETrue) +#define TTEST2(aValue, aExpected) ::Check2(aValue, aExpected, __LINE__, ETrue) + +/////////////////////////////////////////////////////////////////////////////////////// + +//Creates file session instance and the test directory +void CreateTestEnv() + { + TInt err = TheFs.Connect(); + TEST2(err, KErrNone); + + err = TheFs.MkDir(KTestDir); + TEST(err == KErrNone || err == KErrAlreadyExists); + } + +//Starts the SQL server process. +TInt StartSqlServer() + { + const TUid KSqlSrvUid3 = {0x10281E17};//The same UID is in SqlSrv.mmp file + const TUidType serverUid(KNullUid, KNullUid, KSqlSrvUid3); + _LIT(KSqlSrvImg, "SqlSrv");//SQL server image name + RProcess server; + TInt err = server.Create(KSqlSrvImg, KNullDesC, serverUid); + if(err != KErrNone) + { + return err; + } + TRequestStatus stat; + server.Rendezvous(stat); + if(stat != KRequestPending) + { + server.Kill(0); // abort startup + } + else + { + server.Resume(); // logon OK - start the server + } + User::WaitForRequest(stat); // wait for start or death + // we can't use the 'exit reason' if the server panicked as this + // is the panic 'reason' and may be '0' which cannot be distinguished + // from KErrNone + err = (server.ExitType() == EExitPanic) ? KErrGeneral : stat.Int(); + server.Close(); + return err; + } + +////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////// RTestSqlDbSession ////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////// + +//Test client SQL session class +class RTestSqlDbSession : public RSessionBase + { +public: + TInt Connect(const TVersion& aVersion); + void Close(); + TInt SendReceive(TInt aFunction); + TInt SendReceive(TInt aFunction, const TIpcArgs& aArgs); + +private: + TInt DoCreateSession(const TVersion& aVersion); + }; + +TInt RTestSqlDbSession::Connect(const TVersion& aVersion) + { + TInt err = DoCreateSession(aVersion); + if(err == KErrNone) + { + TIpcArgs ipcArgs(KTestDbName1().Length(), &KTestDbName1(), 0, 0); + err = SendReceive(ESqlSrvDbOpen, ipcArgs); + } + if(err != KErrNone && err != KErrAlreadyExists) + { + Close(); + } + return err; + } + +void RTestSqlDbSession::Close() + { + if(Handle()) + { + (void)SendReceive(ESqlSrvDbClose); + } + RSessionBase::Close(); + } + +TInt RTestSqlDbSession::SendReceive(TInt aFunction) + { + return RSessionBase::SendReceive(aFunction); + } + +TInt RTestSqlDbSession::SendReceive(TInt aFunction, const TIpcArgs& aArgs) + { + return RSessionBase::SendReceive(aFunction, aArgs); + } + +TInt RTestSqlDbSession::DoCreateSession(const TVersion& aVersion) + { + const TInt KTimesToRetryConnection = 2; + TInt retry = KTimesToRetryConnection; + _LIT(KSqlSrvName, "!SQL Server");//SqlDb server name + for(;;) + { + TInt err = CreateSession(KSqlSrvName, aVersion); + if(err != KErrNotFound && err != KErrServerTerminated) + { + return err; + } + if(--retry == 0) + { + return err; + } + err = ::StartSqlServer(); + if(err != KErrNone && err != KErrAlreadyExists) + { + return err; + } + } + } + +////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////// + +TInt SendReceive(RTestSqlDbSession aSession, TSqlSrvHandleType aHandleType, TInt aFunction, TInt aHandle, TIpcArgs& aArgs) + { + return aSession.SendReceive(::MakeMsgCode(static_cast (aFunction), aHandleType, aHandle), aArgs); + } + +TInt SendReceive(RTestSqlDbSession aSession, TInt aFunction, TIpcArgs& aArgs) + { + return aSession.SendReceive(aFunction, aArgs); + } + +void PrintIterationCount(TInt aIteration) + { + if((aIteration % 100) == 0) + { + TTime time; + time.HomeTime(); + TDateTime dt = time.DateTime(); + TBuf<16> tbuf; + tbuf.Format(_L("%02d:%02d:%02d.%06d"), dt.Hour(), dt.Minute(), dt.Second(), dt.MicroSecond()); + RDebug::Print(_L("-----[%S] Test iterations: %d\r\n"), &tbuf, aIteration); + } + } + +//Worker thread function. +//It behaves as a malicious client. Connects to the SQL server. In each test iteration generates some random values +//for the function number, handle, handle type, IPC arguments. Then sends a command to the server using these +//randomly generated values. If the server crashes and the thread function receives KErrServerTerminated error, +//then the thread kills itself and the main thread will get KPanicCategory and KPanicCode as a reason for the +//worker thread's death. The last set of randomly generated values will be stored in the memory, pointed by aData argument. +TInt ThreadFunc1(void* aData) + { + __UHEAP_MARK; + + CTrapCleanup* tc = CTrapCleanup::New(); + TTEST(tc != NULL); + + TThreadData* p = static_cast (aData); + TTEST(p != NULL); + TThreadData& data = *p; + + TVersion sqlSoftwareVersion(KSqlMajorVer, KSqlMinorVer, KSqlBuildVer); + RTestSqlDbSession sess; + TInt err = sess.Connect(sqlSoftwareVersion); + TTEST2(err, KErrNone); + + while(++data.iIteration <= KTestIterCount) + { + PrintIterationCount(data.iIteration); + TIpcArgs args; + do + { + data.iFunction = Math::Rand(data.iSeed) % (ESqlSrvStreamClose + 1);//ESqlSrvStreamClose - the last server message number) + } + while(data.iFunction >= ESqlSrvResourceMark && data.iFunction <= ESqlSrvSetHeapFailure); + for(TInt i=0;i (Math::Rand(data.iSeed) % ELastArgType); + switch(data.iArgType[i]) + { + case EIntArgType: + data.iIntArg[i] = Math::Rand(data.iSeed) % 9711; + args.Set(i, data.iIntArg[i]); + break; + case ETextArgType: + { + TInt len = Math::Rand(data.iSeed) % KMaxDesArgLen; + data.iTextArg[i].SetLength(len); + args.Set(i, &data.iTextArg[i]); + } + break; + case EBinArgType: + { + TInt len = Math::Rand(data.iSeed) % KMaxDesArgLen; + data.iBinArg[i].SetLength(len); + args.Set(i, &data.iBinArg[i]); + } + break; + default: + User::Panic(KPanicCategory2, KPanicCode2); + break; + } + } + //Send arguments + User::SetJustInTime(EFalse); + TInt err = KErrNone; + if((Math::Rand(data.iSeed) % 5) == 0) //Pass a handle (statement or stream) + { + data.iHandleType = (Math::Rand(data.iSeed) % 2) ? ESqlSrvStatementHandle : ESqlSrvStreamHandle; + data.iHandle = Math::Rand(data.iSeed) % 64; + err = ::SendReceive(sess, data.iHandleType, data.iFunction, data.iHandle, args); + } + else + { + err = ::SendReceive(sess, data.iFunction, args); + } + if(err == KErrServerTerminated) + { + User::Panic(KPanicCategory, KPanicCode); + } + User::SetJustInTime(ETrue); + } + + sess.Close(); + + delete tc; + + __UHEAP_MARKEND; + + return KErrNone; + } + +/** +@SYMTestCaseID SYSLIB-SQL-CT-1769 +@SYMTestCaseDesc In a loop, where the loop iterations are less than KTestIterCount (5000 at the moment), + the test creates a public shared database and a worker thread, which will behave as + malicious client. If the worker thread crashes the SQL server, then the worker thread + dies notifying the main thread about the SQL server crash. The main thread prints the + values used in the last IPC call and crashes the test. +@SYMTestPriority High +@SYMTestActions SQL, Malicious client simulation test. +@SYMTestExpectedResults Test must not fail +@SYMREQ REQ5792 + REQ5793 + REQ10405 + REQ10407 +*/ +void BadClientTest() + { + TThreadData* p = new TThreadData; + TEST(p != NULL); + TThreadData& data = *p; + data.iFunction = 0; + TTime now; + now.UniversalTime(); + data.iSeed = now.Int64(); + + _LIT(KThreadName, "WorkThrd"); + + for(data.iIteration=0;data.iIteration= 0); + } + db.Close(); + //Run the malicious client (one worker theread which will try to crash the SQL server) + RThread thread; + TEST2(thread.Create(KThreadName, &ThreadFunc1, 0x2000, 0x1000, 0x10000, &data, EOwnerProcess), KErrNone); + TRequestStatus status; + thread.Logon(status); + TEST2(status.Int(), KRequestPending); + thread.Resume(); + User::WaitForRequest(status); + User::SetJustInTime(ETrue); // enable debugger panic handling + if(thread.ExitType() == EExitPanic) + { + if(thread.ExitReason() == KPanicCode) + { + TheTest.Printf(_L("##Server terminated!\r\n")); + TheTest.Printf(_L("##Iteration=%d, Handle type(hex)=%X, Function(hex)=%X, Handle=%d\r\n"), data.iIteration, data.iHandleType, data.iFunction, data.iHandle); + for(TInt i=0;i= 0); + db.Close(); + + RSqlSecurityPolicy sp = CreateSecurityPolicy(); + err = db.Create(KTestDbName2, sp); + TEST2(err, KErrNone); + sp.Close(); + err = db.Exec(_L("CREATE TABLE A(I INTEGER)")); + TEST(err >= 0); + db.Close(); + + TheTest.Printf(_L("Bad names test - public shared database\r\n")); + err = db.Open(KTestDbName1); + TEST2(err, KErrNone); + DoBadNameTest(db); + db.Close(); + + TheTest.Printf(_L("Bad names test - public secure shared database\r\n")); + err = db.Open(KTestDbName2); + TEST2(err, KErrNone); + DoBadNameTest(db); + db.Close(); + + (void)RSqlDatabase::Delete(KTestDbName2); + (void)RSqlDatabase::Delete(KTestDbName1); + + err = RSqlDatabase::Copy(invalidFileName1, invalidFileName2); + TheTest.Printf(_L("Copy database, err=%d\r\n"), err); + TEST(err != KErrNone); + err = RSqlDatabase::Delete(invalidFileName1); + TheTest.Printf(_L("Delete database-1, err=%d\r\n"), err); + TEST(err != KErrNone); + err = RSqlDatabase::Delete(invalidFileName2); + TheTest.Printf(_L("Delete database-2, err=%d\r\n"), err); + TEST(err != KErrNone); + } + +/** +@SYMTestCaseID PDS-SQL-CT-4200 +@SYMTestCaseDesc Invalid sql software version test. +@SYMTestPriority High +@SYMTestActions The test verifies that the SQL server checks that the software version of SQL sessions + to be created is less or equal to the current version of the server software. + If that is not true then the SQL server does not create the session annd returns KErrNotSupported. +@SYMTestExpectedResults Test must not fail +@SYMDEF DEF145236 +*/ +void InvalidSoftwareVersionTest() + { + (void)RSqlDatabase::Delete(KTestDbName1); + RSqlDatabase db; + TInt err = db.Create(KTestDbName1); + TEST2(err, KErrNone); + db.Close(); + + //Smaller version number + TVersion sqlSoftwareVersion1(1, 0, 0); + RTestSqlDbSession sess1; + err = sess1.Connect(sqlSoftwareVersion1); + sess1.Close(); + TEST2(err, KErrNone); + + //Bigger version number 1 + TVersion sqlSoftwareVersion2(1, 97, 3); + RTestSqlDbSession sess2; + err = sess2.Connect(sqlSoftwareVersion2); + TEST2(err, KErrNotSupported); + + //Bigger version number 2 + TVersion sqlSoftwareVersion3(78, 0, 1); + RTestSqlDbSession sess3; + err = sess3.Connect(sqlSoftwareVersion3); + TEST2(err, KErrNotSupported); + + //The current version number + TVersion sqlSoftwareVersion4(KSqlMajorVer, KSqlMinorVer, KSqlBuildVer); + RTestSqlDbSession sess4; + err = sess4.Connect(sqlSoftwareVersion4); + sess4.Close(); + TEST2(err, KErrNone); + + (void)RSqlDatabase::Delete(KTestDbName1); + } + +void DoTests() + { + TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1769 Bad client test ")); + BadClientTest(); + TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4048 Bad names test")); + BadNameTest(); + TheTest.Next(_L(" @SYMTestCaseID:PDS-SQL-CT-4200 Invalid software version test")); + InvalidSoftwareVersionTest(); + } + +TInt E32Main() + { + TheTest.Title(); + + CTrapCleanup* tc = CTrapCleanup::New(); + + __UHEAP_MARK; + + DeleteTestFiles(); + CreateTestEnv(); + DoTests(); + DeleteTestFiles(); + TheFs.Close(); + + __UHEAP_MARKEND; + + TheTest.End(); + TheTest.Close(); + + delete tc; + + User::Heap().Check(); + return KErrNone; + }