Logo
programming4us
programming4us
programming4us
programming4us
Home
programming4us
XP
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone
 
Windows Server

SQL Server 2005 : SQLCLR Security and Reliability Features (part 1) - The Quest for Code Safety

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
9/6/2011 3:13:32 PM
Unlike stored procedures, triggers, UDFs, and other types of code modules that can be exposed within SQL Server, a given SQLCLR routine is not directly related to a database, but rather to an assembly cataloged within the database. Cataloging of an assembly is done using SQL Server's CREATE ASSEMBLY statement, and unlike their T-SQL equivalents, SQLCLR modules get their first security restrictions not via grants, but rather at the same time their assemblies are cataloged. The CREATE ASSEMBLY statement allows the DBA or database developer to specify one of three security and reliability permission sets that dictate what the code in the assembly is allowed to do.

The allowed permission sets are SAFE, EXTERNAL_ACCESS, and UNSAFE. Permissions granted by each set are nested to include the lower sets' permissions. The set of permissions allowed for SAFE assemblies includes limited access to math and string functions, along with data access to the host database via the context connection. The EXTERNAL_ACCESS permission set adds the ability to communicate outside of the SQL Server instance, to other database servers, file servers, web servers, and so on. And the UNSAFE permission set gives the assembly the ability to do pretty much anything—including running unmanaged code.

Although exposed as only a single user-controllable setting, internally each permission set's rights are actually enforced by two distinct methods. Assemblies assigned to each permission set are granted access to do certain operations via .NET's Code Access Security (CAS) technology. At the same time, access is limited to certain operations based on checks against a.NET 2.0 attribute called HostProtectionAttribute (HPA). On the surface, the difference between HPA and CAS is that they are opposites: CAS permissions dictate what an assembly can do, whereas HPA permissions dictate what an assembly cannot do. The combination of everything granted by CAS and everything denied by HPA makes up each of the three permission sets.

Beyond this basic difference is a much more important differentiation between the two access control methods. Although violation of a permission enforced by either method will result in a runtime exception, the actual checks are done at very different times. CAS grants are checked dynamically at run time via a stack walk done as code is executed. On the other hand, HPA permissions are checked at the point of just-in-time compilation—just before calling the method being referenced.

To observe how these differences affect the way code runs, a few test cases will be necessary. To begin with, let's take a look at how a CAS exception works. Create a new assembly containing the following CLR stored procedure:

[SqlProcedure]
public static void CAS_Exception()
{
SqlContext.Pipe.Send("Starting...");

using (System.IO.FileStream fs =
new FileStream(@"c:\b.txt", FileMode.Open))
{
//Do nothing...
}

SqlContext.Pipe.Send("Finished...");

return;
}

Catalog the assembly as SAFE and execute the stored procedure. This will result in the following output:

Starting...
Msg 6522, Level 16, State 1, Procedure CAS_Exception, Line 0
A .NET Framework error occurred during execution of user-defined routine or
aggregate "CAS_Exception":
System.Security.SecurityException: Request for the permission of type
'System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
System.Security.SecurityException:
at System.Security.CodeAccessSecurityEngine.Check(Object demand,
StackCrawlMark& stackMark, Boolean isPermSet)
at System.Security.CodeAccessPermission.Demand()
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32
rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options,
SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
at System.IO.FileStream..ctor(String path, FileMode mode)
at udf_part2.CAS_Exception()
.


The exception thrown in this case is a SecurityException, indicating that this was a CAS violation (of the FileIOPermission type). But the exception is not the only thing that happened; notice that the first line of the output is the string "Starting...", which was output by the SqlPipe.Send method used in the first line of the stored procedure. So before the exception was hit, the method was entered and code execution succeeded until the actual permissions violation was attempted.

NOTE

File I/O is a good example of access to a resource—local or otherwise—that is outside of what the context connection allows. Avoiding this particular violation using the SQLCLR security buckets would require cataloging the assembly using the EXTERNAL_ACCESS permission.

To see how HPA exceptions behave, let's try the same experiment again, this time with the following stored procedure (again, cataloged as SAFE):

[SqlProcedure]
public static void HPA_Exception()
{
SqlContext.Pipe.Send("Starting...");

//The next line will throw an HPA exception...
Monitor.Enter(SqlContext.Pipe);

//Release the lock (if the code even gets here)...
Monitor.Exit(SqlContext.Pipe);

SqlContext.Pipe.Send("Finished...");

return;
}

Just like before, an exception occurs. But this time, the output is a bit different:

Msg 6522, Level 16, State 1, Procedure HPA_Exception, Line 0
A .NET Framework error occurred during execution of user-defined routine or
aggregate "HPA_Exception":
System.Security.HostProtectionException: Attempted to perform an operation that was
forbidden by the CLR host.

The protected resources (only available with full trust) were: All
The demanded resources were: Synchronization, ExternalThreading

System.Security.HostProtectionException:
at System.Security.CodeAccessSecurityEngine.ThrowSecurityException(Assembly asm,
PermissionSet granted, PermissionSet refused, RuntimeMethodHandle rmh,
SecurityAction action, Object demand, IPermission permThatFailed)
at System.Security.CodeAccessSecurityEngine.ThrowSecurityException(Object
assemblyOrString, PermissionSet granted, PermissionSet refused, RuntimeMethodHandle
rmh, SecurityAction action, Object demand, IPermission permThatFailed)
at System.Security.CodeAccessSecurityEngine.CheckSetHelper(PermissionSet grants,
PermissionSet refused, PermissionSet demands, RuntimeMethodHandle rmh, Object
assemblyOrString, SecurityAction action, Boolean throwException)
at System.Security.CodeAccessSecurityEngine.CheckSetHelper(CompressedStack cs,
PermissionSet grants, PermissionSet refused, PermissionSet demands,
RuntimeMethodHandle rmh, Assembly asm, SecurityAction action)
at udf_part2.HPA_Exception()
.


Unlike when executing the CAS_Exception stored procedure, this time we do not see the "Starting..." message, indicating that the SqlPipe.Send method was not called before hitting the exception. As a matter of fact, the HPA_Exception method was not ever entered at all during the code execution phase. You can verify this by attempting to set a breakpoint inside of the function and starting a debug session in Visual Studio. The reason that the breakpoint can't be hit is that the permissions check was done, and the exception thrown, immediately after just-in-time compilation.

You should also note that the wording of the exception is quite a bit different in this case. The wording of the CAS exception is a rather benign "Request for the permission ... failed." On the other hand, the HPA exception carries a much sterner warning: "Attempted to perform an operation that was forbidden." This difference in wording is not accidental. CAS grants are concerned with security—keep code from being able to access something protected because it's not supposed to have access. HPA permissions, on the other hand, are concerned with server reliability and keeping the CLR host running smoothly and efficiently. Threading and synchronization are considered potentially threatening to reliability and are therefore limited to assemblies marked as UNSAFE.

NOTE

Using Reflector or another .NET disassembler, it is possible to explore the Base Class Library to see how the HPA attributes are used for various classes and methods. For instance, the Monitor class is decorated with the following attribute that controls host access: [ComVisible(true), HostProtection(SecurityAction.LinkDemand, Synchronization=true, ExternalThreading=true)].

The Quest for Code Safety

You might be wondering why I'm covering the internals of the SQLCLR permission sets and how their exceptions differ, when fixing the exceptions is so easy: simply raise the permission level of the assemblies to EXTERNAL_ACCESS or UNSAFE and give the code access to do what it needs to do. The fact is, raising the permission levels will certainly work, but by doing so you may be circumventing the security policy, instead of working with it to make your system more secure.

As mentioned in the previous section, code access permissions are granted at the assembly level rather than the method or line level. Therefore, raising the permission of a given assembly in order to make a certain module work can actually affect many different modules contained within the assembly, giving them all enhanced access. Granting additional permissions on several modules within an assembly can in turn create a maintenance burden: if you want to be certain that there are no security problems, you must review each and every line of code in every module to make sure it's not doing anything it's not supposed to do—you can no longer trust the engine to check for you.

You might now be thinking that the solution is simple: split up your methods so that each resides in a separate assembly, and then grant permissions that way. Then, each method really will have its own permission set. But even in that case, permissions may not be granular enough to avoid code review nightmares. Consider a complex 5,000-line module that requires a single file I/O operation to read some lines from a text file. By giving the entire module EXTERNAL_ACCESS permissions, it can now read the lines from that file. But of course, you still have to check all of the remaining code to make sure it's not doing anything unauthorized.

Then there is the question of the effectiveness of manual code review. Is doing a stringent review every time any change is made enough to ensure that the code won't cause problems that would be detected by the engine if the code was marked SAFE? And do you really want to have to do a stringent review before deployment every time any change is made? In the following section, I will show you how to eliminate many of these problems by taking advantage of assembly dependencies in your SQLCLR environment.

Other -----------------
- SQL Server 2005 : Wrapping Code to Promote Cross-Tier Reuse
- SharePoint 2010 Search : Setting Up the Crawler - Crawling Exchange Public Folders & Crawling Line-of-Business Data
- SharePoint 2010 Search : Setting Up the Crawler - Crawling File Shares & Crawling Web Sites
- Migrating to Windows Small Business Server 2011 Standard : Migrating Settings and Data (part 5) - Re-Enabling Folder Redirection
- Migrating to Windows Small Business Server 2011 Standard : Migrating Settings and Data (part 4) - Migrating Users and Groups
- Migrating to Windows Small Business Server 2011 Standard : Migrating Settings and Data (part 3) - Migrate Network Settings & Migrate Exchange Mailboxes and Settings
- Migrating to Windows Small Business Server 2011 Standard : Migrating Settings and Data (part 2) - Configure the Network
- Migrating to Windows Small Business Server 2011 Standard : Migrating Settings and Data (part 1) - Starting the Migration Wizard
- Migrating to Windows Small Business Server 2011 Standard : Creating a Migration Answer File
- Microsoft Dynamics CRM 2011 : Copying Campaign Records & Using Quick Campaigns
 
 
Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
 
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server