diff -r 48780e181b38 -r 578be2adaf3e Symbian3/PDK/Source/GUID-E93D3767-0F74-5335-8233-8236908F70AF.dita --- a/Symbian3/PDK/Source/GUID-E93D3767-0F74-5335-8233-8236908F70AF.dita Tue Jul 20 12:00:49 2010 +0100 +++ b/Symbian3/PDK/Source/GUID-E93D3767-0F74-5335-8233-8236908F70AF.dita Fri Aug 13 16:47:46 2010 +0100 @@ -1,347 +1,347 @@ - - - - - -How -to share file handles between processesThis section describes the sharing of file handles between two -processes, and the APIs provided for this purpose. This feature is only supported -on Symbian platform versions with EKA2 architecture. -

It is possible to share file handles between two processes, allowing an -open file to be passed from one process to another. This is a necessary feature -in secure versions of Symbian platform.

-

Some further implementation considerations are provided to support this -mechanism. A description of passing file handles is given, followed by examples, -which show you how to implement a binary using this feature.

-

See also

-

File Server Client -Side Overview

-

Platform security.

-

This section contains the following topics:

- -
Overview

Allowing -an open file to be passed from one process to another is a necessary feature -in secure versions of Symbian platform. The platform security model provides -a data caging mechanism, allowing processes and the OS itself to hide -private data from other processes.

However, while it is desirable -to keep a file safe from other processes, it is useful to give a specific -process access to the file:

    -
  • without the need to -give that process any special capabilities

  • -
  • without the need to -give the recipient of the file the full path name of that file.

  • -

New RFile member functions enable an open file -handle to be passed from client to a server, from server to a client or from -one process to another process.

Note that file handles are not really -handles in the usual sense of referring to a kernel object, but are simply -numbers that refer to an open file within a file server session.

-
APIs that support -the sharing of file handles

The following RFile member -functions support the sharing of file handles between processes:

    -
  • RFile::AdoptFromClient()

  • -
  • RFile::AdoptFromServer()

  • -
  • RFile::AdoptFromCreator()

  • -
  • RFile::TransferToServer()

  • -
  • RFile::TransferToClient()

  • -
  • RFile::TransferToProcess()

  • -
  • RFile::Name()

  • -
  • RFile::Duplicate()

  • -

The owner of an open Rfile object uses the Transfer***() member -functions to transfer ownership of that object to another process. Note that -the file-server session must be marked as shareable by calling RFs::ShareProtected() before -any file handles are transferred, otherwise the Transfer***() functions -return KErrBadHandle.

A receiving process uses -the Adopt***() member functions to adopt an RFile object -passed from another process.

A receiving process uses the RFile::Name() member -function to retrieve the file name and extension (but not the path) from the -adopted RFile object. This is needed mainly by recognisers, -which sometimes examine a file’s extension to determine whether it is valid -or not.

The RFile::Duplicate() member function -allows a process to clone a received RFile object so that, -for example, two separate functions or threads in the receiving process can -read the file independently.

As another example, consider a client -that only grants access to its data caged private area files, to a -specific system server. The process that opens the file and shares it (using -one of the Transfer***() functions) controls read and write -access to the file, while the corresponding client or server simply calls -one of the Adopt***() functions. In effect, the Adopt***() functions -behave like a file opening API such as RFile::temp(), RFile::Create() and RFile::Open(). -The adopted file retains the access attributes of the file set by the process -doing the sharing. The access attributes of the file can be changed by the -adopting process if the security model permits it.

The following sections -present example code and describe how to share a file between two processes. -This example code uses a simple server that offers the kind of APIs required -to implement the sharing. Details of this server are not given.

Note -that for the sake of clarity, there is no error checking in the example code.

-
Example 1 - -Client passing a file handle to a server

In this example, a client -passes an open file’s handle to a server. The server in turn passes the handle -over to a second server.

The example assumes that the paths and files -used exist and are correct. A file server session (it is recommended that -this session is used specifically for this purpose) is set as shared by -calling RFs::ShareProtected(). This enables the session -to be used by another process. The file is then opened (it exists in the client’s -private directory). The subsession handle and the fileserver session are then -passed to the server using RFile::TransferToServer(). The -file handle can now be adopted by the server’s process.

Client code:

- - RFileHandleSharer handsvr; // handle to server1 - User::LeaveIfError(handsvr.Connect()); // connect to server1 - CleanupClosePushL(handsvr); - RFs fs; - User::LeaveIfError(fs.Connect()); - CleanupClosePushL(fs); - User::LeaveIfError(fs.ShareProtected()); - - RFile file; - User::LeaveIfError(file.Open(fs, _L("test.txt"), EFileRead)); - CleanupClosePushL(file); - - - // store the RFs handle in message slot 0 and the RFile handle in slot 1 - TIpcArgs ipcArgs; - User::LeaveIfError(file.TransferToServer(ipcArgs, 0, 1)); - - // send to server - User::LeaveIfError(handsvr.SendReceive(EMsgXXX, ipcArgs)); - - // ...continue to use file - // - - CleanupStack::PopAndDestroy(3); // close file, fs, and handsvr -

Server1 code:

- - void CFHSession::PassFileHandleL(const RMessage2& aMsg) - { - RFileHandleSharer2 handsvr2; // connect to server2 - User::LeaveIfError(handsvr2.Connect()); - CleanupClosePushL(handsvr2); - - RFile file; - - // Adopt the file using the RFs handle from message slot 0 and the RFile handle from slot 1 - User::LeaveIfError(file.AdoptFromClient(aMsg, 0, 1)); - CleanupClosePushL(file); - - // Use the file - // … - - - // pass the file handle on to server2 - TIpcArgs ipcArgs; - User::LeaveIfError(file.TransferToServer(ipcArgs, 0, 1)); - User::LeaveIfError(handsvr2.SendReceive(EMsgXXX, ipcArgs)); - - // continue to use file - // … - - CleanupStack::PopAndDestroy(2); // close file and handsvr2 - - aMsg.Complete(KErrNone); - } - -

Server2 code:

- - void CFHSession2::PassFileHandleL(const RMessage2& aMsg) - { - RFile file; - - // Adopt the file using the RFs handle from message slot 0 and the RFile handle from slot 1 - User::LeaveIfError(file.AdoptFromClient(aMsg, 0, 1)); - CleanupClosePushL(file); - - // ..use the file - - CleanupStack::PopAndDestroy(); // close file - - aMsg.Complete(KErrNone); - } - -
-
Example 2 - -Client requesting a file handle from a server

This example is similar -to Example -1 but there are some differences.

A client connects to a server -that provides a shared fileserver session and a file handle to an open file -when requested.

Client code:

- - RFileHandleSharer handsvr; // handle to server - User::LeaveIfError(handsvr.Connect()); // connect to server - CleanupClosePushL(handsvr); - - // Retrieve the RFs and RFile handles from the server - TInt fsh; // session (RFs) handle - TPckgBuf<TInt> fh; // sub-session (RFile) handle - - fsh = handsvr.SendReceive(EMsgXXX, TIpcArgs(&fh)); // pointer to fh in slot 0 - User::LeaveIfError(fsh); - -// Adopt the file using the returned handles -RFile file; -User::LeaveIfError(file.AdoptFromServer(fsh, fh())); - CleanupClosePushL(file); - -// ..use the file -// - - CleanupStack::PopAndDestroy(2); // close file and handsvr - -

Server code:

- - void CFHSession::GetFileHandleL(const RMessage2& aMsg) - { - RFs fs; - User::LeaveIfError(fs.Connect()); - CleanupClosePushL(fs); - - User::LeaveIfError(fs.ShareProtected()); - - RFile file; - User::LeaveIfError(file.Open(fs, _L("test.txt"), EFileRead)); - - // transfer to client: store the RFile handle into the package buffer in slot 0 - // and complete the message with the RFs handle - // NB this assumes that if TransferToClient() return an error, then - // the standard CServer2::RunError() will complete the message - User::LeaveIfError(file.TransferToClient(aMsg, 0)); - ASSERT(aMsg.IsNull()); // message should have been completed - - file.Close(); - CleanupStack::PopAndDestroy(1); // fs - } - -
-
Example 3 - -Client passing a file handle to another process

Creator code:

- - RFs fs; - User::LeaveIfError(fs.Connect()); - CleanupClosePushL(fs); - - User::LeaveIfError(fs.ShareProtected()); - - RFile file; - User::LeaveIfError(file.Open(fs, _L("test.txt"), EFileRead)); - CleanupClosePushL(file); - - // create test process - RProcess p; - User::LeaveIfError(p.Create(_L("FHServer.exe"), KNullDesC)); - CleanupClosePushL(p); - - // transfer to process storing the RFs handle into environment slot 1 and the RFile handle into slot 2 - // NB slot 0 is reserved for the command line - User::LeaveIfError(file.TransferToProcess(p, 1, 2)); - - // Wait for handle to be transferred; wrap in an active object if blocking this thread is undesirable - TRequestStatus transStatus; - p.Rendezvous(transStatus); - - if(transStatus != KRequestPending) - { // Process creation failed - p.RendezvousCancel(transStatus); - p.Kill(0); - User:Leave(transStatus.Int()); - } - // Start the process - p.Resume(); - - - User::WaitForRequest(transStatus); - User::LeaveIfError(transfStatus.Int()); - - // Now we can safely close the fs - CleanupStack::PopAndDestroy(3); // close p, file, and fs - -

Created process code:

- - RFile file; - - // Adopt the file using the RFs handle into environment slot 1 and the RFile handle into slot 2 - User::LeaveIfError(file.AdoptFromCreator(1)); - CleanupClosePushL(file); - RProcess::Rendezvous(KErrNone); // Signal transfer completed successfully - - // ..use the file - // - - CleanupStack::PopAndDestroy(); // close file - -
-
Implementation -Considerations

An RFile object contains two handles:

    -
  • a file (or subsession) -handle

  • -
  • a file server handle

  • -

When a file handle is adopted by the receiver, the new RFile object -that is created by the Adopt***() member functions contains -a duplicate of the sender’s file server handle. This new RFile object, -however, has a flag set in the subsession handle to allow it to close its -associated file server handle automatically whenever RFile::Close() is -called. This removes the need to maintain a separate RFs object -when adopting a file.

Security issues

It is strongly recommended that the -process from which a shared file originates, opens a file server session specifically -for this purpose, and closes it after it has finished using the shared file. -This is because the session handle is shared along with the file handle, and -therefore, any other files opened in that session may be accessible to the -other process. The receiving process can increment file handle numbers -(remember file handles are only numbers) and gain access to files.

It -is also recommended that the adopting process does not open other files with -the session it receives, as the process that shared the file may do the same.

RFs and RFile lifetime issues

The RFile subsession -handle passed to Transfer***() and Adopt***() member -functions is duplicated by the Transfer***() functions so -that the original RFile handle can either be closed immediately -or used for a period and then closed. This is because it is not the same handle -as the one being adopted.

If there is no need to continue using the RFile handle, -then the RFs handle can be safely closed as follows:

    -
  • For TransferToServer() or AdoptFromClient(), -the RFs handle can be safely closed once the server has -called AdoptFromClient(). This would normally be done on -return from a synchronous call.

  • -
  • For TransferToClient() or AdoptFromServer(), -the RFs handle can be safely closed once the server has -called TransferToClient().

  • -
  • For TransferToProcess() or AdoptFromCreator(), -the RFs handle can be safely closed once the client has -called TransferToProcess().

  • -
-
Testing

Extensive -testing of implementations of this mechanism are not required as, in effect, -you are simply using a file server subsession (RFile) API. -It is recommended that you test the client-server system, but that will be -specific to how you use it. If it works you have probably implemented it correctly, -provided you adhere to the security considerations of the shared file.

-
Summary

Passing -files between processes is a useful tool, but it is important that you adhere -to the security advice.

To share a file handle, take the following -steps:

    -
  1. Ensure the file exists. -A file to be shared between two processes is a resource that lives in a system -or private location for security.

  2. -
  3. Set the fileserver session -as shareable so that it can be used by more that one process. A fileserver -session (as with all server sessions) is a Kernel object.

  4. -
  5. Transfer the session -handle and the subsession handle from the open file using one of the RFile Transfer***() member -functions and the message passing system between client and server.

  6. -
  7. Use one of the RFile Adopt***() member -functions to begin using the handles in the receiving process.

  8. -
  9. Once you have finished, -close the received RFile object.

  10. -
+ + + + + +How +to share file handles between processesThis section describes the sharing of file handles between two +processes, and the APIs provided for this purpose. This feature is only supported +on Symbian platform versions with EKA2 architecture. +

It is possible to share file handles between two processes, allowing an +open file to be passed from one process to another. This is a necessary feature +in secure versions of Symbian platform.

+

Some further implementation considerations are provided to support this +mechanism. A description of passing file handles is given, followed by examples, +which show you how to implement a binary using this feature.

+

See also

+

File Server Client +Side Overview

+

Platform security.

+

This section contains the following topics:

+
    +
  • Overview

  • +
  • APIs that support the sharing of file handles

  • +
  • Example 1 - Client passing a file handle to a server

  • +
  • Example 2 - Client requesting a file handle from a server

  • +
  • Example 3 - Client passing a file handle to another process

  • +
  • Implementation Considerations

  • +
  • Testing

  • +
  • Summary.

  • +
+
Overview

Allowing +an open file to be passed from one process to another is a necessary feature +in secure versions of Symbian platform. The platform security model provides +a data caging mechanism, allowing processes and the OS itself to hide +private data from other processes.

However, while it is desirable +to keep a file safe from other processes, it is useful to give a specific +process access to the file:

    +
  • without the need to +give that process any special capabilities

  • +
  • without the need to +give the recipient of the file the full path name of that file.

  • +

New RFile member functions enable an open file +handle to be passed from client to a server, from server to a client or from +one process to another process.

Note that file handles are not really +handles in the usual sense of referring to a kernel object, but are simply +numbers that refer to an open file within a file server session.

+
APIs that support +the sharing of file handles

The following RFile member +functions support the sharing of file handles between processes:

    +
  • RFile::AdoptFromClient()

  • +
  • RFile::AdoptFromServer()

  • +
  • RFile::AdoptFromCreator()

  • +
  • RFile::TransferToServer()

  • +
  • RFile::TransferToClient()

  • +
  • RFile::TransferToProcess()

  • +
  • RFile::Name()

  • +
  • RFile::Duplicate()

  • +

The owner of an open Rfile object uses the Transfer***() member +functions to transfer ownership of that object to another process. Note that +the file-server session must be marked as shareable by calling RFs::ShareProtected() before +any file handles are transferred, otherwise the Transfer***() functions +return KErrBadHandle.

A receiving process uses +the Adopt***() member functions to adopt an RFile object +passed from another process.

A receiving process uses the RFile::Name() member +function to retrieve the file name and extension (but not the path) from the +adopted RFile object. This is needed mainly by recognisers, +which sometimes examine a file’s extension to determine whether it is valid +or not.

The RFile::Duplicate() member function +allows a process to clone a received RFile object so that, +for example, two separate functions or threads in the receiving process can +read the file independently.

As another example, consider a client +that only grants access to its data caged private area files, to a +specific system server. The process that opens the file and shares it (using +one of the Transfer***() functions) controls read and write +access to the file, while the corresponding client or server simply calls +one of the Adopt***() functions. In effect, the Adopt***() functions +behave like a file opening API such as RFile::temp(), RFile::Create() and RFile::Open(). +The adopted file retains the access attributes of the file set by the process +doing the sharing. The access attributes of the file can be changed by the +adopting process if the security model permits it.

The following sections +present example code and describe how to share a file between two processes. +This example code uses a simple server that offers the kind of APIs required +to implement the sharing. Details of this server are not given.

Note +that for the sake of clarity, there is no error checking in the example code.

+
Example 1 - +Client passing a file handle to a server

In this example, a client +passes an open file’s handle to a server. The server in turn passes the handle +over to a second server.

The example assumes that the paths and files +used exist and are correct. A file server session (it is recommended that +this session is used specifically for this purpose) is set as shared by +calling RFs::ShareProtected(). This enables the session +to be used by another process. The file is then opened (it exists in the client’s +private directory). The subsession handle and the fileserver session are then +passed to the server using RFile::TransferToServer(). The +file handle can now be adopted by the server’s process.

Client code:

+ + RFileHandleSharer handsvr; // handle to server1 + User::LeaveIfError(handsvr.Connect()); // connect to server1 + CleanupClosePushL(handsvr); + RFs fs; + User::LeaveIfError(fs.Connect()); + CleanupClosePushL(fs); + User::LeaveIfError(fs.ShareProtected()); + + RFile file; + User::LeaveIfError(file.Open(fs, _L("test.txt"), EFileRead)); + CleanupClosePushL(file); + + + // store the RFs handle in message slot 0 and the RFile handle in slot 1 + TIpcArgs ipcArgs; + User::LeaveIfError(file.TransferToServer(ipcArgs, 0, 1)); + + // send to server + User::LeaveIfError(handsvr.SendReceive(EMsgXXX, ipcArgs)); + + // ...continue to use file + // + + CleanupStack::PopAndDestroy(3); // close file, fs, and handsvr +

Server1 code:

+ + void CFHSession::PassFileHandleL(const RMessage2& aMsg) + { + RFileHandleSharer2 handsvr2; // connect to server2 + User::LeaveIfError(handsvr2.Connect()); + CleanupClosePushL(handsvr2); + + RFile file; + + // Adopt the file using the RFs handle from message slot 0 and the RFile handle from slot 1 + User::LeaveIfError(file.AdoptFromClient(aMsg, 0, 1)); + CleanupClosePushL(file); + + // Use the file + // … + + + // pass the file handle on to server2 + TIpcArgs ipcArgs; + User::LeaveIfError(file.TransferToServer(ipcArgs, 0, 1)); + User::LeaveIfError(handsvr2.SendReceive(EMsgXXX, ipcArgs)); + + // continue to use file + // … + + CleanupStack::PopAndDestroy(2); // close file and handsvr2 + + aMsg.Complete(KErrNone); + } + +

Server2 code:

+ + void CFHSession2::PassFileHandleL(const RMessage2& aMsg) + { + RFile file; + + // Adopt the file using the RFs handle from message slot 0 and the RFile handle from slot 1 + User::LeaveIfError(file.AdoptFromClient(aMsg, 0, 1)); + CleanupClosePushL(file); + + // ..use the file + + CleanupStack::PopAndDestroy(); // close file + + aMsg.Complete(KErrNone); + } + +
+
Example 2 - +Client requesting a file handle from a server

This example is similar +to Example +1 but there are some differences.

A client connects to a server +that provides a shared fileserver session and a file handle to an open file +when requested.

Client code:

+ + RFileHandleSharer handsvr; // handle to server + User::LeaveIfError(handsvr.Connect()); // connect to server + CleanupClosePushL(handsvr); + + // Retrieve the RFs and RFile handles from the server + TInt fsh; // session (RFs) handle + TPckgBuf<TInt> fh; // sub-session (RFile) handle + + fsh = handsvr.SendReceive(EMsgXXX, TIpcArgs(&fh)); // pointer to fh in slot 0 + User::LeaveIfError(fsh); + +// Adopt the file using the returned handles +RFile file; +User::LeaveIfError(file.AdoptFromServer(fsh, fh())); + CleanupClosePushL(file); + +// ..use the file +// + + CleanupStack::PopAndDestroy(2); // close file and handsvr + +

Server code:

+ + void CFHSession::GetFileHandleL(const RMessage2& aMsg) + { + RFs fs; + User::LeaveIfError(fs.Connect()); + CleanupClosePushL(fs); + + User::LeaveIfError(fs.ShareProtected()); + + RFile file; + User::LeaveIfError(file.Open(fs, _L("test.txt"), EFileRead)); + + // transfer to client: store the RFile handle into the package buffer in slot 0 + // and complete the message with the RFs handle + // NB this assumes that if TransferToClient() return an error, then + // the standard CServer2::RunError() will complete the message + User::LeaveIfError(file.TransferToClient(aMsg, 0)); + ASSERT(aMsg.IsNull()); // message should have been completed + + file.Close(); + CleanupStack::PopAndDestroy(1); // fs + } + +
+
Example 3 - +Client passing a file handle to another process

Creator code:

+ + RFs fs; + User::LeaveIfError(fs.Connect()); + CleanupClosePushL(fs); + + User::LeaveIfError(fs.ShareProtected()); + + RFile file; + User::LeaveIfError(file.Open(fs, _L("test.txt"), EFileRead)); + CleanupClosePushL(file); + + // create test process + RProcess p; + User::LeaveIfError(p.Create(_L("FHServer.exe"), KNullDesC)); + CleanupClosePushL(p); + + // transfer to process storing the RFs handle into environment slot 1 and the RFile handle into slot 2 + // NB slot 0 is reserved for the command line + User::LeaveIfError(file.TransferToProcess(p, 1, 2)); + + // Wait for handle to be transferred; wrap in an active object if blocking this thread is undesirable + TRequestStatus transStatus; + p.Rendezvous(transStatus); + + if(transStatus != KRequestPending) + { // Process creation failed + p.RendezvousCancel(transStatus); + p.Kill(0); + User:Leave(transStatus.Int()); + } + // Start the process + p.Resume(); + + + User::WaitForRequest(transStatus); + User::LeaveIfError(transfStatus.Int()); + + // Now we can safely close the fs + CleanupStack::PopAndDestroy(3); // close p, file, and fs + +

Created process code:

+ + RFile file; + + // Adopt the file using the RFs handle into environment slot 1 and the RFile handle into slot 2 + User::LeaveIfError(file.AdoptFromCreator(1)); + CleanupClosePushL(file); + RProcess::Rendezvous(KErrNone); // Signal transfer completed successfully + + // ..use the file + // + + CleanupStack::PopAndDestroy(); // close file + +
+
Implementation +Considerations

An RFile object contains two handles:

    +
  • a file (or subsession) +handle

  • +
  • a file server handle

  • +

When a file handle is adopted by the receiver, the new RFile object +that is created by the Adopt***() member functions contains +a duplicate of the sender’s file server handle. This new RFile object, +however, has a flag set in the subsession handle to allow it to close its +associated file server handle automatically whenever RFile::Close() is +called. This removes the need to maintain a separate RFs object +when adopting a file.

Security issues

It is strongly recommended that the +process from which a shared file originates, opens a file server session specifically +for this purpose, and closes it after it has finished using the shared file. +This is because the session handle is shared along with the file handle, and +therefore, any other files opened in that session may be accessible to the +other process. The receiving process can increment file handle numbers +(remember file handles are only numbers) and gain access to files.

It +is also recommended that the adopting process does not open other files with +the session it receives, as the process that shared the file may do the same.

RFs and RFile lifetime issues

The RFile subsession +handle passed to Transfer***() and Adopt***() member +functions is duplicated by the Transfer***() functions so +that the original RFile handle can either be closed immediately +or used for a period and then closed. This is because it is not the same handle +as the one being adopted.

If there is no need to continue using the RFile handle, +then the RFs handle can be safely closed as follows:

    +
  • For TransferToServer() or AdoptFromClient(), +the RFs handle can be safely closed once the server has +called AdoptFromClient(). This would normally be done on +return from a synchronous call.

  • +
  • For TransferToClient() or AdoptFromServer(), +the RFs handle can be safely closed once the server has +called TransferToClient().

  • +
  • For TransferToProcess() or AdoptFromCreator(), +the RFs handle can be safely closed once the client has +called TransferToProcess().

  • +
+
Testing

Extensive +testing of implementations of this mechanism are not required as, in effect, +you are simply using a file server subsession (RFile) API. +It is recommended that you test the client-server system, but that will be +specific to how you use it. If it works you have probably implemented it correctly, +provided you adhere to the security considerations of the shared file.

+
Summary

Passing +files between processes is a useful tool, but it is important that you adhere +to the security advice.

To share a file handle, take the following +steps:

    +
  1. Ensure the file exists. +A file to be shared between two processes is a resource that lives in a system +or private location for security.

  2. +
  3. Set the fileserver session +as shareable so that it can be used by more that one process. A fileserver +session (as with all server sessions) is a Kernel object.

  4. +
  5. Transfer the session +handle and the subsession handle from the open file using one of the RFile Transfer***() member +functions and the message passing system between client and server.

  6. +
  7. Use one of the RFile Adopt***() member +functions to begin using the handles in the receiving process.

  8. +
  9. Once you have finished, +close the received RFile object.

  10. +
\ No newline at end of file