From d430540f8868079930a9cddce79a6bc00ffdc7bd Mon Sep 17 00:00:00 2001 From: Steve Beattie Date: Fri, 10 Nov 2017 14:42:43 -0800 Subject: [PATCH] TechnicalDoc_Mount_Flags: initial markdown conversion --- TechnicalDoc_Mount_Flags.md | 251 ++++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 TechnicalDoc_Mount_Flags.md diff --git a/TechnicalDoc_Mount_Flags.md b/TechnicalDoc_Mount_Flags.md new file mode 100644 index 0000000..a78dfcf --- /dev/null +++ b/TechnicalDoc_Mount_Flags.md @@ -0,0 +1,251 @@ +Encoding Mount options +====================== + +Mount options encompass two distinct sets of data, the mount flags, +and the fs options that are encoded in different ways. + +Separating mount flags from fs data options +------------------------------------------- + +Mount options are are parsed and any that match the a table of +predefined mount flags are removed to be encoded as mount flags, +the rest are treated as fs mount options. + +Encoding of Mount flags +======================= + +The flags of mount rules use a special encoding to allow for a trianary +match (present, not present, don't care) against a bit set. + +The mnt flags set follows the kernel mount flag set, that is a 32 +bit mask in the same numerical order as stored in the Linux kernel. +```C + #define MS_RDONLY (1 << 0) + #define MS_RW (0 << 0) + #define MS_NOSUID (1 << 1) + #define MS_SUID (0 << 1) + #define MS_NODEV (1 << 2) + #define MS_DEV (0 << 2) + #define MS_NOEXEC (1 << 3) + #define MS_EXEC (0 << 3) + #define MS_SYNC (1 << 4) + #define MS_ASYNC (0 << 4) + #define MS_REMOUNT (1 << 5) + #define MS_MAND (1 << 6) + #define MS_NOMAND (0 << 6) + #define MS_DIRSYNC (1 << 7) + #define MS_NODIRSYNC (0 << 7) + #define MS_NOATIME (1 << 10) + #define MS_ATIME (0 << 10) + #define MS_NODIRATIME (1 << 11) + #define MS_DIRATIME (0 << 11) + #define MS_BIND (1 << 12) + #define MS_MOVE (1 << 13) + #define MS_REC (1 << 14) + #define MS_VERBOSE (1 << 15) + #define MS_SILENT (1 << 15) + #define MS_LOAD (0 << 15) + #define MS_ACL (1 << 16) + #define MS_NOACL (0 << 16) + #define MS_UNBINDABLE (1 << 17) + #define MS_PRIVATE (1 << 18) + #define MS_SLAVE (1 << 19) + #define MS_SHARED (1 << 20) + #define MS_RELATIME (1 << 21) + #define MS_NORELATIME (0 << 21) + #define MS_IVERSION (1 << 23) + #define MS_NOIVERSION (0 << 23) + #define MS_STRICTATIME (1 << 24) + #define MS_NOUSER (1 << 31) + #define MS_USER (0 << 31) +``` + +Notice that some flags have a bit shift value while other flags +are defined as 0. The flags defined as 0 have no bit set, as these +flags they are represent by the absence of the flag, that is they +are represent by a 0 value in the noted bit position; e.g. MS\_RW is +true when MS\_RDONLY is not set. + +Each flags is encoded as a single byte value equal to its bit shift + +1. So MS\_RDONLY is encoded as 0 + 1 = 1, and MS\_RW is not directly +encoded. With each bit that is encoded being written in bit order. + +For example, the flags set (MS\_RDONLY | MS\_NODEV | MS\_NOACL | MS\_NOUSER) is encoded as the ordered match: + +``` + (MS_RDONLY shift + 1)(MS_NODEV shift + 1)(MS_NOUSER shift + 1) +``` + +*Note*: MS\_NOACL is not encoded because it is represented by the +MS\_ACL bit not being set + +A "don't care" flag is encoded as an alternation of the flag shift + +1, and the empty set (MS\_RDONLY shift + 1|). + +For example, using the same flags from above as don't care values +(MS\_RDONLY | MS\_NODEV | MS\_NOACL | MS\_NOUSER) would be encoded as + +``` + (MS_RDONLY shift + 1|)(MS_NODEV shift + 1|)(MS_ACL shift + 1|)(MS_NOUSER shift + 1|) +``` + +*Note*: MS\_NOACL is now represented by (MS\_ACL shift + 1|), this +is because declaring a flag as a don't care value means it can take +on either value. + +To match against a mount rule's flag set. The requested flag set +is search in bit order and match attempt are made against the set +bits. That is for a bit set (MS\_RDONLY|MS\_NODEV) only the character +(MS\_RDONLY shift + 1) and (MS\_NODEV shift + 1) are matched against +in that order. + +E.G. the dfa state matching for (MS\_RDONLY|MS\_NODEV) is +```C + next_state = dfa_match(state, MS_RD_ONLY shift + 1) + next_state = dfa_match(next_state, MS_NODEV + 1) +``` + +Why this works +-------------- + +A mount rule using = for its options (mount option=( )) encodes an +exact pattern of bits. Flags that are not specified are taken to be +their 0 value, and flags that have a 0 value are ignored. The string +of set flags makes a unique string much like the character string '1 3 +7'. To match this string only those bits can be set in the flags mask, +an unset bit does not lead to progression through the match string, +a flag that is set that is not in the string results in match failure. + +E.G. (MS\_RDONLY shift | MS\_NODEV shift | MS\_ATIME | MS\_ACL) +is encoded as the string '1 3 16', notice MS\_ATIME is dropped. + +- Trying to match (MS\_NOSUID) against this results in the string + of '2', which clearly does not match (it fails in the first + character), and can not progress, as 1 will never be matched as + the string is always generated in numerically increasing order. + +- Trying to match (MS\_RDONLY shift | MS\_NODEV shift ) against + it result in as string of '1 3' which will match the first 2 + characters but can not progress to the last character. + +- Trying to match (MS\_RDONLY shift | MS\_NODEV shift | MS\_ACL | + MS\_NOUSER) results in a string of '1 3 16 32' which matches for + the requisite 3 characters, but the MS_NOUSER bit forces the match + to move out of an accepting state and fail. The accept permission + is encoded only in the on the states that exactly match and moving + out of them results in no permission.` + +The DFA can efficiently encode multiple rules information, allowing +for a single pass match against all rules. + +Encoding of flags when using **options in (set)** +------------------------------------------------- + +When options are specified using the **in** keyword. The flags are +treated as don't care values because the **in** option defines a subset +of values that can be specified. Any flag that is not specified by +the **in** subset is treated as a 0 value unless there is also an +exact match **options=()** set. + +This means that + +``` + options in (ro) +``` + +is equivalent to + +``` + options=(ro,rw) +``` + +and for allow rules is just a convenient short hand for expressing +a set of flags that may or may not be set. Matching of these values +works similar to the matches shown above except the string defines +a pattern match + +Example: mount options in (ro,nouser): + +- defines the bitset (MS\_RDONLY | MS\_NOUSER), which makes the + match string (1|) (32|) which is equivalent to the following set + of strings + + - '' - the empty string '1' + - '32' - '1 32' + +Example: mount options in (ro,acl) options=(nodev,nouser) + +- defines the 2 bitsets (MS\_RDONLY | MS\_ACL) and (MS\_NODEV | + MS\_NOUSER) which defines the match string (1|) 3 (16|) 32 which + is equivalent to the following set of strings + + ``` + '3 32' + '1 3 32' + '1 3 16 32' + '3 16 32' + ``` + +### Short cut encoding for all flags + +If all flags are optional the regular expression `[^\x00]*` is used + +Encoding deny flag rules +------------------------ + +Because of the way flags are matched the strings used to match deny +rules need to be encoded differently in the don't care cases. The +exact match cases (options=()) follows the same encoding as the allow +rules. The reason two different string encodings are used is that +exact match cases defines exactly 1 string that can be matched but, +the don't care cases define a set of strings, and the semantics of +the set is inverted by the deny. + +For example, deny options in (ro, acl), does NOT mean +``` + deny '' - emtpy string + deny ro, + deny acl, + deny ro acl, +``` +But rather means deny any match containing ro or acl, that is +``` + deny ro, + deny ro nosuid, + deny ro nodev, + deny ro nosuid nodev, + deny ro ... +``` + +Where deny options=(ro) means deny the case where ro is the only flag set. + +To represent the don't care flags deny rule we use an alternation +with a pattern matching all flags + +Example: options in (ro, acl), is represented as: +``` + deny ([^\x00]*1[^\x00]|[^\x00]*16[^\x00]) +``` + +This allows the rule to intersect all mount rules that could contain +ro or acl flags. + +### combining don't care and exact match + +When options and exact match string are combined the alternation gets modified + +???? + +### Short cut encoding for denying all flags + +If a deny rule encodes both the set and unset forms of a flag +(eg. options=(rw,ro) or options in (ro)) this results in all flags +being denied because a positive flags match is not possible because +during a match there are only 2 possible values for each flag and +both values are denied. + +This is match in this case is encoded with the regular expression +`[^\x00]*` + +Encoding of FS specific options +===============================