SELinux has been through several iterations as part of the process of being incorporated into the Linux kernel. During this time, the overall architecture has remained the same, but many of the programmatic details have changed. Some of the reasons for change were: requirements for upstream acceptance; changes in LSM as part of being accepted into the kernel; and the switch to using xattrs.
As one example of the changes between kernel versions, originally security context was maintained through a mapping from context to SID, and managed by the security server. In the 2.6.x Linux kernel, the security context for a file is stored in the xattrs, allowing it to carry around its own SELinux context.
As an implementation of the Flask architecture, SELinux also served as a reference implementation of LSM. Originally LSM and SELinux were patches to the 2.4.<x> series of kernels; SELinux was never able to work as a loadable security module. Therefore, a big part of gaining upstream acceptance into the mainline Linux kernel required everything from fixing coding practices to changing how SELinux interacted with the kernel.
Part of the SELinux development team was also instrumental in designing, building, and integrating LSM into the kernel. SELinux integration into the kernel was the motivation to start the LSM project. SELinux was an early proof of the ability of LSM to allow security-enhancements to be connected into, instead of strapped onto, the Linux kernel. Originally, SELinux was a loadable module, but it became statically compiled into the 2.6.x kernel. It is still an LSM module, using the LSM hooks in the kernel to control and label. Because of the abstraction layer provided by both the LSM and Flask frameworks, SELinux is highly configurable and modifiable.
Flask is flexible enough to work in many different environments, and Linux is a natural fit for the Flask model. Access to the kernel source and a willing, community-driven development process allow for the best modification to fully support Flask's objectives. The wide range of platforms Linux runs on means SELinux is extensively tested. The consensus process of getting SELinux integrated into the kernel has improved the code and practices. Now that it is integrated, it has a better chance of long-term success than security-enhancement models that are strapped on-top of the operating system.
There are a few more differences in the specific way SELinux implements Flask in the Linux kernel, compared to traditional Flask methodology and initial SELinux creation:
Under traditional TE, there is a distinction between types and domains. A type is the security context for a file object, and a domain is the security context for a process. In the SELinux implementation, there is no real distinction programmatically. In SELinux, domains are processes that have the attribute process, so the term domain is used in the traditional way. Similarly, the term type is mostly applied to object types, but it can mean both domains and types.
The term security server is still used for the sake of clarity, but it is no longer a stand-alone service. The security server, the AVC, and the policy engine are now all parts of the kernel.