Breaking the Singleton Design Pattern
A little more about reflection: Another post in my blog
More about singleton: Wikipedia: Singleton pattern
This semester, I have taken part in a course in Master program at HCMUT. Recently, the lecturer is disappointed because the number of students attending the class is so low. So I went to class this morning.
The lecture was about design patterns. At the moment I entered the room, the lecturer demonstrated Singleton patterns and the content was quite simple. When he said that the constructor of the class must be non public so that the outside world wouldn't be able to instantiate a new instance of that class, the first thing came into my mind: REFLECTION. What if there is a man in the outside world, try attacking the principle of singleton by reflection.
The lecturer prefers C# and by chance, I am working with that language, so I will use it as the language of all code in this entry. Also, in this entry, I will play 2 roles: the man trying attacking singleton pattern and the man maintaining the correctness of the pattern.
I prepared a Double-Check Locking implementation of Singleton Pattern. You can find the original from here on Microsoft website. All I did was renaming the class into Girlfriend.
You see, you may not have a girlfriend, or if you have, you have only one at a time.
Firstly, I get an instance of Girlfriend for comparing later. I also prepare a place for another girl.
Girlfriend gf1 = Girlfriend.Instance;
Girlfriend gf2 = null;
Secondly, I write a comparing method. And here is the sub-program that will show the comparation result between girls.
Then, I analyze the code, which is available on the internet. I know that the constructor is set private, so I can not simply call it for creating another Girlfriend instance.
Reflection technique may help in this situation, here what I do: get the constructor, then invoke it.
Type type = typeof(Girlfriend);
if (type != null)
{
ConstructorInfo ci = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null);
if (ci != null)
{
try {
gf2 = (Girlfriend)ci.Invoke(null);
} catch {}
}
}
Lastly, I call the comparing method to observe the result:
Now see the result:
One of my friends suggest me to check the invokers which invoke the constructor and allow only ones those are inside the definition of Girlfriend class.
To do so, I have to complete these works:
- Generate a privacy helper class that comparing 2 invokers' info
- Get the name of every invokers at the beginning of every constructions
- Allow only invokers those are members of the class, otherwise, throw another exception.
Th attacker used reflection to attack and break my Singleton twice. Now is the time I use reflection in my defense and fight back.
The below code is how I improve my code:
You can easily understand the classes. There is only 1 point that need to be explained. In the method IsInvocationAllowed, I call new StackTrace().GetFrame(2) ? Do you wonder why?
My intent is that when the Constructor called, it will call the method IsInvocationAllowed from helper class to verify something and when IsInvocationAllowed executed, the CallStack will be like this
position 0 - IsInvocationAllowed method
position 1 - Girlfriend constructor
position 2 - the invoker invoking the constructor
It's clearly that getting frame number 2 gives me the invoker's infomation.
After my improvement, the attacker will not be able to create the second girlfriend any more, and here is the result:
The score is equalized: Reflection 2 - 2 Singleton
First step is ok, the static Girlfriend instance of the class is set to null successfully.
Second step is not ok, an exception is thrown again.
And after hours of thinking, I know that I am so stupid. When the static instance is null, why do I have to call the constructor myself? Just let the Singleton itself generates another Girlfriend for me.
I am not sure if this is working. But at least it decreases the possibility of being failed, because it reduces the amount of works that reflection does and let the Singleton generator does some.
Temporarily I have no other way to pass the condition checking from the defender. So I try this idea. modifying the second step into "Let the singleton does its job"
The line
gf2 = (Girlfriend)ci.Invoke(null);
is replaced by
gf2 = Girlfriend.Instance;
Then I run the code
What have we here? Two girls, available, and different from each other, and both mine.
This round I win, again. The defender must work harder to protect his code from being breaking.
More about singleton: Wikipedia: Singleton pattern
This semester, I have taken part in a course in Master program at HCMUT. Recently, the lecturer is disappointed because the number of students attending the class is so low. So I went to class this morning.
The lecture was about design patterns. At the moment I entered the room, the lecturer demonstrated Singleton patterns and the content was quite simple. When he said that the constructor of the class must be non public so that the outside world wouldn't be able to instantiate a new instance of that class, the first thing came into my mind: REFLECTION. What if there is a man in the outside world, try attacking the principle of singleton by reflection.
The lecturer prefers C# and by chance, I am working with that language, so I will use it as the language of all code in this entry. Also, in this entry, I will play 2 roles: the man trying attacking singleton pattern and the man maintaining the correctness of the pattern.
I prepared a Double-Check Locking implementation of Singleton Pattern. You can find the original from here on Microsoft website. All I did was renaming the class into Girlfriend.
public sealed class Girlfriend { private static volatile Girlfriend instance; private static object syncRoot = new Object(); private Girlfriend() {} public static Girlfriend Instance { get { if (instance == null) { lock (syncRoot) { if (instance == null) instance = new Girlfriend(); } } return instance; } } } |
Figure 1 - Original Singleton implementation |
You see, you may not have a girlfriend, or if you have, you have only one at a time.
Round 1 - Reflection v1 vs Singleton v1
My role here is the attacker.Firstly, I get an instance of Girlfriend for comparing later. I also prepare a place for another girl.
Girlfriend gf1 = Girlfriend.Instance;
Girlfriend gf2 = null;
Secondly, I write a comparing method. And here is the sub-program that will show the comparation result between girls.
void ShowComparation(string, title, Girlfriend gf1, Girlfriend gf2) { Console.WriteLine(title); Console.WriteLine("Gf1 is null = " + (gf1 == null)); Console.WriteLine("Gf2 is null = " + (gf2 == null)); Console.WriteLine("Gf1 is Gf2 = " + (gf1 == gf2)); Console.ReadLine(); } |
Figure 2 - Comparing method |
Then, I analyze the code, which is available on the internet. I know that the constructor is set private, so I can not simply call it for creating another Girlfriend instance.
Reflection technique may help in this situation, here what I do: get the constructor, then invoke it.
Type type = typeof(Girlfriend);
if (type != null)
{
ConstructorInfo ci = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null);
if (ci != null)
{
try {
gf2 = (Girlfriend)ci.Invoke(null);
} catch {}
}
}
Lastly, I call the comparing method to observe the result:
I got 2 girls and they are different. The singleton pattern implementation goes wrong.
Reflection 1 - 0 Singleton
Round 2 - Singleton v2 vs Reflection v1
My role here is the defender.
Because my current implementation goes wrong when someone invoked my private constructor successfully, I will set up a condition there.
The constructor now has to check if the instance is created. If it exists, the constructor must throw an exception to interrupt the initiating of a new object.
Here is the new constructor.
private Girlfriend()
{
if (instance != null)
{
throw new Exception("Can not have 2 girldfriends at the same time");
}
}
Replace the one constructor by the new one, I have the modified Double-Check Locking implementation of Singleton pattern: public sealed class Girlfriend { private static volatile Girlfriend instance; private static object syncRoot = new Object(); private Girlfriend() { if (instance != null)
{
throw new Exception("Can not have 2 girldfriends at the same time");
}
}public static Girlfriend Instance { get { if (instance == null) { lock (syncRoot) { if (instance == null) instance = new Girlfriend(); } } return instance; } } } | ||
Figure 3 - Modified Singleton implementation Ok, let the attacker run his code again and wait for the result:
He got only 1 girlfriend who is gf1 and gf2 is not available for him now.
Reflection 1 - 1 Singleton
Round 3 - Reflection v2 vs Singleton v2
I am the attacker again.
By a little debugging, I recognize that when I invoke the constructor of Girlfriend class, an exception thrown preventing me create my second Girlfriend object.
Logically, I think that the defender changed code inside the constructor to throw an exception whenever a Girlfriend instance exists.Or, I don't have to think, I just use decompiler to read the modified in code. I think of a strategy with 3 steps: Step 1: I copy the instance to a backup and set it to null Step 2: I invoke the constructor normally Step 3: I restore the instance like nothing happened Here we go:
|
Now see the result:
I did it one more time and got 2 girls.
Reflection 2 - 1 Singleton
Round 4 - Singleton with a little Reflection a.k.a Singleton v3
The attacker's code is ahead mine again. As the one who keeps the implementation goes right. What should I do? I am thinking. No idea shows up. So I write a blog post and ask for help.One of my friends suggest me to check the invokers which invoke the constructor and allow only ones those are inside the definition of Girlfriend class.
To do so, I have to complete these works:
- Generate a privacy helper class that comparing 2 invokers' info
- Get the name of every invokers at the beginning of every constructions
- Allow only invokers those are members of the class, otherwise, throw another exception.
Th attacker used reflection to attack and break my Singleton twice. Now is the time I use reflection in my defense and fight back.
The below code is how I improve my code:
public class MethodBaseComparer : IEqualityComparer<MethodBase>
{
private string GetMethodIdentifier(MethodBase mb)
{
return mb.Name + ":" + String.Join(";", mb.GetParameters().Select(paramInfo => paramInfo.Name).ToArray());
}
public bool Equals(MethodBase m1, MethodBase m2)
{
return this.GetMethodIdentifier(m1) == this.GetMethodIdentifier(m2);
}
public int GetHashCode(MethodBase mb)
{
return this.GetMethodIdentifier(mb).GetHashCode();
}
}
public class PrivacyHelper
{
public static bool IsInvocationAllowed<T>()
{
Type curType = typeof(T);
MethodBase[] lstMethod = curType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static).ToArray();
MethodBase invoker = new StackTrace().GetFrame(2).GetMethod();
if (lstMethod == null)
return false;
else
return lstMethod.Contains(invoker, new MethodBaseComparer());
}
}
|
Figure 4 - Privacy helper and comparer classes
|
You can easily understand the classes. There is only 1 point that need to be explained. In the method IsInvocationAllowed, I call new StackTrace().GetFrame(2) ? Do you wonder why?
My intent is that when the Constructor called, it will call the method IsInvocationAllowed from helper class to verify something and when IsInvocationAllowed executed, the CallStack will be like this
position 0 - IsInvocationAllowed method
position 1 - Girlfriend constructor
position 2 - the invoker invoking the constructor
It's clearly that getting frame number 2 gives me the invoker's infomation.
After my improvement, the attacker will not be able to create the second girlfriend any more, and here is the result:
The score is equalized: Reflection 2 - 2 Singleton
Round 5 - The attacker is so stupid
Hi, it's me, the attacker. The last time I run my code, I see that gf2 is no longer available. I review my steps with debugger to find where thing goes wrong.First step is ok, the static Girlfriend instance of the class is set to null successfully.
Second step is not ok, an exception is thrown again.
And after hours of thinking, I know that I am so stupid. When the static instance is null, why do I have to call the constructor myself? Just let the Singleton itself generates another Girlfriend for me.
I am not sure if this is working. But at least it decreases the possibility of being failed, because it reduces the amount of works that reflection does and let the Singleton generator does some.
Temporarily I have no other way to pass the condition checking from the defender. So I try this idea. modifying the second step into "Let the singleton does its job"
The line
gf2 = (Girlfriend)ci.Invoke(null);
is replaced by
gf2 = Girlfriend.Instance;
Then I run the code
What have we here? Two girls, available, and different from each other, and both mine.
This round I win, again. The defender must work harder to protect his code from being breaking.
Comments
Post a Comment