Proposal for Category in plugin environment

I recently found a problem with Category in plugin environment. It was due to power of Objective-C. However, we need to put restriction on its functionality when necessary.

When we use Category in our own program, it is very powerful. Category allows to overriding some messages of classes we didn’t write. With C++, you should create a child class of such parent class and override some methods of the parent class. However with Objective-C, you just write messages which override existing messages at the level of the super class.

Now, let’s consider a hosting program which loads its plugins or frameworks you write. In plugins’ or frameworks’ codes, you defines a category which override some existing classes’ messages. You can safely guess that every lines of codes which calls the same message in your plugins/frameworks codes, they will use your version of the messages. Now, how about the host program? I thought that host program is separated from plugins/frameworks physically, when some codes in the host program calls the same messages, I didn’t expect that it would call my version of messages. What I expected was that the host program code will call original messages or if it overrides those messages for itself, then it will call its overridden messages.

However, my guess was wrong. Apple’s document mentiones that plugins/frameworks’ codes are to be loaded onto the same memory sapce as the host program.
It also stated that if you have multiple plugins/frameworks for each of them to override same messages, the runtime doesn’t guarantee what will be called first. What is called can be different from invocation to invocation.

However, this description cleverly get away from very important and crucial behaviour. If you once know the problem, you will recognize suddenly that the description can be understood such a way, but if you don’t know the problem, the setence doesn’t say anything about the dangerous behaviour.

So, here I would like to suggest adding a few keywords to Category declaration or interface.

1. keyword-based Approach

@interface(unified) ExistingClassName ( CategoryName )
...
@end

The (unified) means that the category is to be effective in memory space of the host program. If there is no (unified) stated, the overriding by category is to be restricted to the specific plugin codes only. It should not affect other plugins. Alternative form can be

@interface(unified=true) ExistingClassName ( CategoryName )
...
@end

@interface(unified=false) ExistingClassName ( CategoryName )
...
@end

or

@interface(unified) ExistingClassName ( CategoryName )
...
@end

@interface(nonunified) ExistingClassName ( CategoryName )
...
@end

On host side, there should be some project setting or Runtime environment configuration function to enable and disable if the specific program you write would allow its plugins category can be effective in memory space of the host program or not. Then we have some combinations.

Host Program Plugin Code Category Behaviour
Unified Unified Unified
Unified Non-Unified Non-Unified
Non-Unified Unified Non-Unified
Non-Unified Non-Unified Non-Unified

2. Registration/Contract-based approach

In addition to the first approach, it should be able to negotiate between a host program and the plugin program about whether to allow “unified” behaviour or not.
This is necessary when a host program set “non-unified” mode. If “unified” mode is set for the host program, it is the host program writer’s responsibility to write such “open” host program.

The scope of this approach is, therefore, when a host program is set to non-unified mode, and depending on some agreed-upon keys or something like security descriptor, it is possible for a plugin to work in “unified” mode. It is a plugin which asks a host to allow “unified” mode for the plugin. (but not for other plugins)
In the plugin which obtained the privilege, you can freely define category and it can affect the memory space of the host program. Whether this is in effect for other plugins or not is in question. However, at least, it should be in effect for the host program. This is to allow ingest legible codes into the host program for maximum flexibility.

How is my proposal?

21 responses to this post.

  1. Well, I think you got something wrong about categories. Categories are not necessary for plugins. You can just subclass any class like in C++. Categories are usually used when you want to extend an existing class with a new function that will automagically become available for all subclasses. Overriding something using a category is something you should only rarely do. And if you do, it gets problematic once you try to override it more than once, as you then will have the implementation of the module loaded last. I don’t know how the Apple runtime handles it, but the ABI of the GNU runtime has a function with __attribute__((constructor)) in each module that registers the module with the runtime. And (at least in my runtime) each time a category is added, the methods are overridden. That means the category loaded last wins – and I assume this is very similar in the Apple runtime.

    As for your proposal, it would need a compiler patch, an ABI patch and a runtime patch. The compiler patch would parse your attribute and the ABI patch would add a new field to the category struct. The runtime then would need to act on that flag.

    For the runtime to act on that flag would be hard – as classes can’t be shared between modules then anymore, but you might need another copy of the class for a module then with a different dispatch table.

    All in all, I don’t see any reason why you would want your suggestion. If you want to control yourself which methods gets replaced, then have a look at class_replaceMethod. Though I think you are doing something wrong when your plugins replace methods multiple times.

    Reply

    • Posted by jongampark on April 5, 2010 at 8:40 AM

      I suggested it because current Host-Plugin architecture doesn’t do anything to prevent a plug-in writer from writing category for existing classes like NSString. It just says “don’t do it.”
      However, I found out that it was possible to define a category in a plug-in codes, and a host program started to use the new definition.
      This allows very powerful plugin which can hi-jack things in host program and enhance it without modifying the host program, but also it imposes danger like that you can ingest malicious codes easily.

      By the way, it could have been better if you left your email. The exact reason I proposed would have been better to be hidden.

      Reply

      • Well, if you use categories to hi-jack things in a program, you’re doing it wrong, as that can’t be reversed. For that, you should use class_replaceMethod, which returns the old method so you can later change it back. This way you can even have multiple plugins that do something and then call the old implementation. But using a category here is just wrong.

        Btw, I left my e-mail address, I also replied to you at the Mailinglist.

        Reply

        • Posted by jongampark on April 5, 2010 at 11:05 AM

          No. I didn’t try hi-jacking anything. But thing is, it can happen without your intention.
          So, my proposal is for more robust architecture.

          Reply

          • Just because something allows you to do something does not mean you need to do it. There are legitimate reasons for categories, like extending a framework. C allows you to shoot yourself in the foot as well, still, would you for example suggest removing pointers because someone could use them in a wrong way?

            Reply

            • Posted by jongampark on April 6, 2010 at 6:32 AM

              You chose wrong example to compare with.
              it is like to say this.
              “Accessing system directory using non-admin users’ process is not good. Just don’t do it. It’s bad.”

              I would rather say,
              “We need to restrict non-admin users’ process in accessing system directory. If they really want to do, they need to acquire proper privilege.”
              I don’t want to let non-admin users’ process just access system directory only by saying “don’t do it”.
              If we follow your example, we should not write any vaccine programs.

              Reply

              • No, actually, the comparison quite fits. Your’s doesn’t. A user should never be able to access an admin’s file. Whereas loading a category – as pointed out above already – makes sense. There are situations where it makes sense. Whereas is never makes sense that a user can access the admin’s files.
                ObjC is based on C. C allows you to shoot yourself in the foot. But that also gives you a lot of flexibility. Get used to it, or use a langauge that tries to prevent you from doing what you want (Java, a scripting language, etc.).

                Reply

                • Posted by jongampark on April 6, 2010 at 9:14 AM

                  You said, “there are situations where it makes sense”. Then it also means that there are situations where it DOESN’T make sense.

                  Then my proposal is better. Mine is not to make impossible to use category for plugin environment. Mine is to allow/disallow it with given keywords or contract between host program and plugin codes.

                  It makes things flexible and stable in security wise.

                  Also, I think your analogy still is not same to the problem itself.

                  Have you think about this situation?
                  A hacker figure out some method which is to be called by host program by nm or class-dump or things like that. He writes a method in Category and suddenly the host program starts to call it.
                  Then it means the hacker can do some bad thing. Finder is a good example. Finder allows plugins. It was carbon based but now it is cocoa based. Then the hacker can easily write some category method and ingest his malicious code easily.

                  “Just don’t do that” is not enough.

                  Reply

        • Posted by jongampark on April 5, 2010 at 1:30 PM

          Oh, I’m sorry that I didn’t check the mailing list. I just checked it.
          I thought the one you left on this blog, js-jongamparkwordpress@webkeks.org, was fake email to prevent spam mail.

          Reply

  2. See above about the technical issue with your proposal and why it would only make things worse. Your proposal tries to solve something which does not need solving. Using categories the way you want is wrong, see above for the correct way to do it.

    The “a hacker can provide a category” scenario is nonsense. You could just LD_PRELOAD (DYLD_PRELOAD on OS X, IIRC, as you seem to be using that) a shared library which will override libc functions.

    Again: You are trying to fix something that is not broken. What you want to do with categories is not what they’re meant for. Your proposal would be similar like allowing dereferencing invalid pointers in some files if you set some compiler flag where it would then point to dereference the nearest valid address.

    Again, C allows you to do bad things if you use it the wrong way. But it does not consider a way right or wrong, so you have the freedom to do what you want. If it breaks, it’s entirely your fault. The same is true for ObjC. C and ObjC come from the Unix world, not the Windows world. Keep that in mind.

    Reply

    • Don’t know why this post was positioned here. Can you please move it where it belongs?

      Reply

      • Posted by jongampark on April 6, 2010 at 9:29 AM

        WordPress comment manager doesn’t seem to allow it. I’m sorry for that.

        Reply

        • This just demonstrates why software should not stop you from doing things the way you want, even if that means you can shoot yourself in the foot :).

          Reply

    • Posted by jongampark on April 6, 2010 at 9:33 AM

      Then can you think of a proper way of solving it?
      Let’s share that.

      NOTE : Whether it is from Windows or Unix is not an issue at all. Why does it matter? I’m also long time Unix developer and have seen lots of people who said such. If there is some problem arises, it should be solved or protected not to happen. That philosophy is same on all platform.

      Reply

      • I already did – see above. The solution for what you want to do is class_replaceMethod.

        Whether it is from Windows or Unix is a matter, because of the philosophy C uses – which the UNIX one. UNIX does not restrict the users, you can do bad stuff. Windows tries to prevent you from that (like deleting a file that is opened by some application). The difference is that one assumes the user is an idiot and the other assumes the user knows what he does. C and ObjC both think the user knows what he’s doing. There is no reason at all to forbid categories in shared libraries – that would be stupid, to say the least. Categories are used to extend frameworks. You can do it the right way, but you can of course always do it the wrong way. If you want a language that prevents you from doing bad things, neither C nor ObjC is for you.

        Reply

        • Posted by jongampark on April 6, 2010 at 10:01 AM

          Oh.. yes. Then Apple should get rid of their keychain service.
          Should get rid of any certification service.

          I see. Thank you very much.

          Reply

          • You do know that you are talking about things that don’t have anything to do with each other, right? Well, I assume you do and only want to troll, thus I’m out of the discussion. You wanted feedback, you got it. But if you want feedback, you also have to take feedback you don’t like.

            Reply

  3. […] proposed a new mechanism to prevent very fragile architecture of Objective-C/Cocoa in loadable bundle or plug… […]

    Reply

  4. […] Mac OS X에서의 보안을 심각하게 훼손할 수있는 문제에 대한 해결법을 제시했었다. 이상한 사람이 말도 안되는 식으로 태클을 걸어서 […]

    Reply

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: