]> Git Repo - J-linux.git/commitdiff
Merge tag 'apparmor-pr-2023-07-06' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <[email protected]>
Fri, 7 Jul 2023 16:55:31 +0000 (09:55 -0700)
committerLinus Torvalds <[email protected]>
Fri, 7 Jul 2023 16:55:31 +0000 (09:55 -0700)
Pull apparmor updates from John Johansen:

 - fix missing error check for rhashtable_insert_fast

 - add missing failure check in compute_xmatch_perms

 - fix policy_compat permission remap with extended permissions

 - fix profile verification and enable it

 - fix kzalloc perms tables for shared dfas

 - Fix kernel-doc header for verify_dfa_accept_index

 - aa_buffer: Convert 1-element array to flexible array

 - Return directly after a failed kzalloc() in two functions

 - fix use of strcpy in policy_unpack_test

 - fix kernel-doc complaints

 - Fix some kernel-doc comments

* tag 'apparmor-pr-2023-07-06' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor:
  apparmor: Fix kernel-doc header for verify_dfa_accept_index
  apparmor: fix: kzalloc perms tables for shared dfas
  apparmor: fix profile verification and enable it
  apparmor: fix policy_compat permission remap with extended permissions
  apparmor: aa_buffer: Convert 1-element array to flexible array
  apparmor: add missing failure check in compute_xmatch_perms
  apparmor: fix missing error check for rhashtable_insert_fast
  apparmor: Return directly after a failed kzalloc() in two functions
  AppArmor: Fix some kernel-doc comments
  apparmor: fix use of strcpy in policy_unpack_test
  apparmor: fix kernel-doc complaints

1  2 
security/apparmor/file.c
security/apparmor/lsm.c
security/apparmor/policy_compat.c
security/apparmor/policy_unpack.c

diff --combined security/apparmor/file.c
index 9119ddda6217909179a75c960ac720b42f4983a1,56061c9ab0188b24c4387863b4b026e837f2341c..698b124e649f6d7c3141bd9de2c6e33a66fef68b
@@@ -161,6 -161,7 +161,7 @@@ static int path_name(const char *op, st
        return 0;
  }
  
+ struct aa_perms default_perms = {};
  /**
   * aa_lookup_fperms - convert dfa compressed perms to internal perms
   * @dfa: dfa to lookup perms for   (NOT NULL)
   *
   * Returns: a pointer to a file permission set
   */
- struct aa_perms default_perms = {};
  struct aa_perms *aa_lookup_fperms(struct aa_policydb *file_rules,
                                 aa_state_t state, struct path_cond *cond)
  {
@@@ -459,7 -459,7 +459,7 @@@ static int __file_path_perm(const char 
  {
        struct aa_profile *profile;
        struct aa_perms perms = {};
 -      vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_user_ns(file),
 +      vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_idmap(file),
                                            file_inode(file));
        struct path_cond cond = {
                .uid = vfsuid_into_kuid(vfsuid),
diff --combined security/apparmor/lsm.c
index f431251ffb9113217142872edf12256b4ac6606d,8d2d31d0d5065e50f58d5368011211c11c1b6932..c9463bd0307df2c9cc99fffd7f2d0676cbfb99a9
@@@ -46,7 -46,7 +46,7 @@@ int apparmor_initialized
  
  union aa_buffer {
        struct list_head list;
-       char buffer[1];
+       DECLARE_FLEX_ARRAY(char, buffer);
  };
  
  #define RESERVE_COUNT 2
@@@ -227,7 -227,8 +227,7 @@@ static int common_perm(const char *op, 
   */
  static int common_perm_cond(const char *op, const struct path *path, u32 mask)
  {
 -      struct user_namespace *mnt_userns = mnt_user_ns(path->mnt);
 -      vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_userns,
 +      vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_idmap(path->mnt),
                                            d_backing_inode(path->dentry));
        struct path_cond cond = {
                vfsuid_into_kuid(vfsuid),
@@@ -272,13 -273,14 +272,13 @@@ static int common_perm_rm(const char *o
                          struct dentry *dentry, u32 mask)
  {
        struct inode *inode = d_backing_inode(dentry);
 -      struct user_namespace *mnt_userns = mnt_user_ns(dir->mnt);
        struct path_cond cond = { };
        vfsuid_t vfsuid;
  
        if (!inode || !path_mediated_fs(dentry))
                return 0;
  
 -      vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
 +      vfsuid = i_uid_into_vfsuid(mnt_idmap(dir->mnt), inode);
        cond.uid = vfsuid_into_kuid(vfsuid);
        cond.mode = inode->i_mode;
  
@@@ -377,7 -379,7 +377,7 @@@ static int apparmor_path_rename(const s
  
        label = begin_current_label_crit_section();
        if (!unconfined(label)) {
 -              struct user_namespace *mnt_userns = mnt_user_ns(old_dir->mnt);
 +              struct mnt_idmap *idmap = mnt_idmap(old_dir->mnt);
                vfsuid_t vfsuid;
                struct path old_path = { .mnt = old_dir->mnt,
                                         .dentry = old_dentry };
                struct path_cond cond = {
                        .mode = d_backing_inode(old_dentry)->i_mode
                };
 -              vfsuid = i_uid_into_vfsuid(mnt_userns, d_backing_inode(old_dentry));
 +              vfsuid = i_uid_into_vfsuid(idmap, d_backing_inode(old_dentry));
                cond.uid = vfsuid_into_kuid(vfsuid);
  
                if (flags & RENAME_EXCHANGE) {
                        struct path_cond cond_exchange = {
                                .mode = d_backing_inode(new_dentry)->i_mode,
                        };
 -                      vfsuid = i_uid_into_vfsuid(mnt_userns, d_backing_inode(old_dentry));
 +                      vfsuid = i_uid_into_vfsuid(idmap, d_backing_inode(old_dentry));
                        cond_exchange.uid = vfsuid_into_kuid(vfsuid);
  
                        error = aa_path_perm(OP_RENAME_SRC, label, &new_path, 0,
@@@ -458,13 -460,13 +458,13 @@@ static int apparmor_file_open(struct fi
  
        label = aa_get_newest_cred_label(file->f_cred);
        if (!unconfined(label)) {
 -              struct user_namespace *mnt_userns = file_mnt_user_ns(file);
 +              struct mnt_idmap *idmap = file_mnt_idmap(file);
                struct inode *inode = file_inode(file);
                vfsuid_t vfsuid;
                struct path_cond cond = {
                        .mode = inode->i_mode,
                };
 -              vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
 +              vfsuid = i_uid_into_vfsuid(idmap, inode);
                cond.uid = vfsuid_into_kuid(vfsuid);
  
                error = aa_path_perm(OP_OPEN, label, &file->f_path, 0,
@@@ -1209,13 -1211,13 +1209,13 @@@ static int apparmor_inet_conn_request(c
  /*
   * The cred blob is a pointer to, not an instance of, an aa_label.
   */
 -struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = {
 +struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = {
        .lbs_cred = sizeof(struct aa_label *),
        .lbs_file = sizeof(struct aa_file_ctx),
        .lbs_task = sizeof(struct aa_task_ctx),
  };
  
 -static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
 +static struct security_hook_list apparmor_hooks[] __ro_after_init = {
        LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
        LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
        LSM_HOOK_INIT(capget, apparmor_capget),
@@@ -1427,7 -1429,7 +1427,7 @@@ static const struct kernel_param_ops pa
        .get = param_get_aaintbool
  };
  /* Boot time disable flag */
 -static int apparmor_enabled __lsm_ro_after_init = 1;
 +static int apparmor_enabled __ro_after_init = 1;
  module_param_named(enabled, apparmor_enabled, aaintbool, 0444);
  
  static int __init apparmor_enabled_setup(char *str)
@@@ -1647,7 -1649,7 +1647,7 @@@ retry
                list_del(&aa_buf->list);
                buffer_count--;
                spin_unlock(&aa_buffers_lock);
-               return &aa_buf->buffer[0];
+               return aa_buf->buffer;
        }
        if (in_atomic) {
                /*
                pr_warn_once("AppArmor: Failed to allocate a memory buffer.\n");
                return NULL;
        }
-       return &aa_buf->buffer[0];
+       return aa_buf->buffer;
  }
  
  void aa_put_buffer(char *buf)
@@@ -1747,7 -1749,7 +1747,7 @@@ static int __init alloc_buffers(void
                        destroy_buffers();
                        return -ENOMEM;
                }
-               aa_put_buffer(&aa_buf->buffer[0]);
+               aa_put_buffer(aa_buf->buffer);
        }
        return 0;
  }
@@@ -1764,6 -1766,11 +1764,6 @@@ static int apparmor_dointvec(struct ctl
        return proc_dointvec(table, write, buffer, lenp, ppos);
  }
  
 -static struct ctl_path apparmor_sysctl_path[] = {
 -      { .procname = "kernel", },
 -      { }
 -};
 -
  static struct ctl_table apparmor_sysctl_table[] = {
        {
                .procname       = "unprivileged_userns_apparmor_policy",
  
  static int __init apparmor_init_sysctl(void)
  {
 -      return register_sysctl_paths(apparmor_sysctl_path,
 -                                   apparmor_sysctl_table) ? 0 : -ENOMEM;
 +      return register_sysctl("kernel", apparmor_sysctl_table) ? 0 : -ENOMEM;
  }
  #else
  static inline int apparmor_init_sysctl(void)
index cc89d1e88fb745993d54941782a5e8089f5ccaa9,7ff9184ace2942a3edd97a0b3e7f3b6ba47ef18d..0cb02da8a3193fc2f5f4cb8f30e36af51dcdbee5
@@@ -146,7 -146,8 +146,8 @@@ static struct aa_perms compute_fperms_o
   *
   * Returns: remapped perm table
   */
- static struct aa_perms *compute_fperms(struct aa_dfa *dfa)
+ static struct aa_perms *compute_fperms(struct aa_dfa *dfa,
+                                      u32 *size)
  {
        aa_state_t state;
        unsigned int state_count;
        table = kvcalloc(state_count * 2, sizeof(struct aa_perms), GFP_KERNEL);
        if (!table)
                return NULL;
+       *size = state_count * 2;
  
 -      /* zero init so skip the trap state (state == 0) */
 -      for (state = 1; state < state_count; state++) {
 +      for (state = 0; state < state_count; state++) {
                table[state * 2] = compute_fperms_user(dfa, state);
                table[state * 2 + 1] = compute_fperms_other(dfa, state);
        }
        return table;
  }
  
- static struct aa_perms *compute_xmatch_perms(struct aa_dfa *xmatch)
+ static struct aa_perms *compute_xmatch_perms(struct aa_dfa *xmatch,
+                                     u32 *size)
  {
        struct aa_perms *perms;
        int state;
        state_count = xmatch->tables[YYTD_ID_BASE]->td_lolen;
        /* DFAs are restricted from having a state_count of less than 2 */
        perms = kvcalloc(state_count, sizeof(struct aa_perms), GFP_KERNEL);
+       if (!perms)
+               return NULL;
+       *size = state_count;
  
        /* zero init so skip the trap state (state == 0) */
        for (state = 1; state < state_count; state++)
@@@ -239,7 -246,8 +245,8 @@@ static struct aa_perms compute_perms_en
        return perms;
  }
  
- static struct aa_perms *compute_perms(struct aa_dfa *dfa, u32 version)
+ static struct aa_perms *compute_perms(struct aa_dfa *dfa, u32 version,
+                                     u32 *size)
  {
        unsigned int state;
        unsigned int state_count;
        table = kvcalloc(state_count, sizeof(struct aa_perms), GFP_KERNEL);
        if (!table)
                return NULL;
+       *size = state_count;
  
        /* zero init so skip the trap state (state == 0) */
        for (state = 1; state < state_count; state++)
@@@ -286,7 -295,7 +294,7 @@@ static void remap_dfa_accept(struct aa_
  /* TODO: merge different dfa mappings into single map_policy fn */
  int aa_compat_map_xmatch(struct aa_policydb *policy)
  {
-       policy->perms = compute_xmatch_perms(policy->dfa);
+       policy->perms = compute_xmatch_perms(policy->dfa, &policy->size);
        if (!policy->perms)
                return -ENOMEM;
  
  
  int aa_compat_map_policy(struct aa_policydb *policy, u32 version)
  {
-       policy->perms = compute_perms(policy->dfa, version);
+       policy->perms = compute_perms(policy->dfa, version, &policy->size);
        if (!policy->perms)
                return -ENOMEM;
  
  
  int aa_compat_map_file(struct aa_policydb *policy)
  {
-       policy->perms = compute_fperms(policy->dfa);
+       policy->perms = compute_fperms(policy->dfa, &policy->size);
        if (!policy->perms)
                return -ENOMEM;
  
index cf2ceec40b28ae17c5f573c36ed5aa4ffb8c2855,35ec2d9b6064e91227a7ce4ba3c11fba94724f52..694fb7a099624b2e476bea0095d406f3db9b40fb
@@@ -161,6 -161,15 +161,6 @@@ VISIBLE_IF_KUNIT bool aa_inbounds(struc
  }
  EXPORT_SYMBOL_IF_KUNIT(aa_inbounds);
  
 -static void *kvmemdup(const void *src, size_t len)
 -{
 -      void *p = kvmalloc(len, GFP_KERNEL);
 -
 -      if (p)
 -              memcpy(p, src, len);
 -      return p;
 -}
 -
  /**
   * aa_unpack_u16_chunk - test and do bounds checking for a u16 size based chunk
   * @e: serialized data read head (NOT NULL)
@@@ -304,26 -313,6 +304,26 @@@ fail
  }
  EXPORT_SYMBOL_IF_KUNIT(aa_unpack_u64);
  
 +static bool aa_unpack_cap_low(struct aa_ext *e, kernel_cap_t *data, const char *name)
 +{
 +      u32 val;
 +
 +      if (!aa_unpack_u32(e, &val, name))
 +              return false;
 +      data->val = val;
 +      return true;
 +}
 +
 +static bool aa_unpack_cap_high(struct aa_ext *e, kernel_cap_t *data, const char *name)
 +{
 +      u32 val;
 +
 +      if (!aa_unpack_u32(e, &val, name))
 +              return false;
 +      data->val = (u32)data->val | ((u64)val << 32);
 +      return true;
 +}
 +
  VISIBLE_IF_KUNIT bool aa_unpack_array(struct aa_ext *e, const char *name, u16 *size)
  {
        void *pos = e->pos;
@@@ -448,7 -437,7 +448,7 @@@ static struct aa_dfa *unpack_dfa(struc
  /**
   * unpack_trans_table - unpack a profile transition table
   * @e: serialized data extent information  (NOT NULL)
-  * @table: str table to unpack to (NOT NULL)
+  * @strs: str table to unpack to (NOT NULL)
   *
   * Returns: true if table successfully unpacked or not present
   */
@@@ -860,10 -849,12 +860,12 @@@ static struct aa_profile *unpack_profil
                }
                profile->attach.xmatch_len = tmp;
                profile->attach.xmatch.start[AA_CLASS_XMATCH] = DFA_START;
-               error = aa_compat_map_xmatch(&profile->attach.xmatch);
-               if (error) {
-                       info = "failed to convert xmatch permission table";
-                       goto fail;
+               if (!profile->attach.xmatch.perms) {
+                       error = aa_compat_map_xmatch(&profile->attach.xmatch);
+                       if (error) {
+                               info = "failed to convert xmatch permission table";
+                               goto fail;
+                       }
                }
        }
  
                profile->path_flags = PATH_MEDIATE_DELETED;
  
        info = "failed to unpack profile capabilities";
 -      if (!aa_unpack_u32(e, &(rules->caps.allow.cap[0]), NULL))
 +      if (!aa_unpack_cap_low(e, &rules->caps.allow, NULL))
                goto fail;
 -      if (!aa_unpack_u32(e, &(rules->caps.audit.cap[0]), NULL))
 +      if (!aa_unpack_cap_low(e, &rules->caps.audit, NULL))
                goto fail;
 -      if (!aa_unpack_u32(e, &(rules->caps.quiet.cap[0]), NULL))
 +      if (!aa_unpack_cap_low(e, &rules->caps.quiet, NULL))
                goto fail;
 -      if (!aa_unpack_u32(e, &tmpcap.cap[0], NULL))
 +      if (!aa_unpack_cap_low(e, &tmpcap, NULL))
                goto fail;
  
        info = "failed to unpack upper profile capabilities";
        if (aa_unpack_nameX(e, AA_STRUCT, "caps64")) {
                /* optional upper half of 64 bit caps */
 -              if (!aa_unpack_u32(e, &(rules->caps.allow.cap[1]), NULL))
 +              if (!aa_unpack_cap_high(e, &rules->caps.allow, NULL))
                        goto fail;
 -              if (!aa_unpack_u32(e, &(rules->caps.audit.cap[1]), NULL))
 +              if (!aa_unpack_cap_high(e, &rules->caps.audit, NULL))
                        goto fail;
 -              if (!aa_unpack_u32(e, &(rules->caps.quiet.cap[1]), NULL))
 +              if (!aa_unpack_cap_high(e, &rules->caps.quiet, NULL))
                        goto fail;
 -              if (!aa_unpack_u32(e, &(tmpcap.cap[1]), NULL))
 +              if (!aa_unpack_cap_high(e, &tmpcap, NULL))
                        goto fail;
                if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
                        goto fail;
        info = "failed to unpack extended profile capabilities";
        if (aa_unpack_nameX(e, AA_STRUCT, "capsx")) {
                /* optional extended caps mediation mask */
 -              if (!aa_unpack_u32(e, &(rules->caps.extended.cap[0]), NULL))
 +              if (!aa_unpack_cap_low(e, &rules->caps.extended, NULL))
                        goto fail;
 -              if (!aa_unpack_u32(e, &(rules->caps.extended.cap[1]), NULL))
 +              if (!aa_unpack_cap_high(e, &rules->caps.extended, NULL))
                        goto fail;
                if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
                        goto fail;
                                      AA_CLASS_FILE);
                if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
                        goto fail;
-               error = aa_compat_map_policy(&rules->policy, e->version);
-               if (error) {
-                       info = "failed to remap policydb permission table";
-                       goto fail;
+               if (!rules->policy.perms) {
+                       error = aa_compat_map_policy(&rules->policy,
+                                                    e->version);
+                       if (error) {
+                               info = "failed to remap policydb permission table";
+                               goto fail;
+                       }
                }
-       } else
+       } else {
                rules->policy.dfa = aa_get_dfa(nulldfa);
+               rules->policy.perms = kcalloc(2, sizeof(struct aa_perms),
+                                             GFP_KERNEL);
+               if (!rules->policy.perms)
+                       goto fail;
+               rules->policy.size = 2;
+       }
        /* get file rules */
        error = unpack_pdb(e, &rules->file, false, true, &info);
        if (error) {
                goto fail;
        } else if (rules->file.dfa) {
-               error = aa_compat_map_file(&rules->file);
-               if (error) {
-                       info = "failed to remap file permission table";
-                       goto fail;
+               if (!rules->file.perms) {
+                       error = aa_compat_map_file(&rules->file);
+                       if (error) {
+                               info = "failed to remap file permission table";
+                               goto fail;
+                       }
                }
        } else if (rules->policy.dfa &&
                   rules->policy.start[AA_CLASS_FILE]) {
                rules->file.dfa = aa_get_dfa(rules->policy.dfa);
                rules->file.start[AA_CLASS_FILE] = rules->policy.start[AA_CLASS_FILE];
-       } else
+               rules->file.perms = kcalloc(rules->policy.size,
+                                           sizeof(struct aa_perms),
+                                           GFP_KERNEL);
+               if (!rules->file.perms)
+                       goto fail;
+               memcpy(rules->file.perms, rules->policy.perms,
+                      rules->policy.size * sizeof(struct aa_perms));
+               rules->file.size = rules->policy.size;
+       } else {
                rules->file.dfa = aa_get_dfa(nulldfa);
+               rules->file.perms = kcalloc(2, sizeof(struct aa_perms),
+                                           GFP_KERNEL);
+               if (!rules->file.perms)
+                       goto fail;
+               rules->file.size = 2;
+       }
        error = -EPROTO;
        if (aa_unpack_nameX(e, AA_STRUCT, "data")) {
                info = "out of memory";
  
                        data->key = key;
                        data->size = aa_unpack_blob(e, &data->data, NULL);
 -                      data->data = kvmemdup(data->data, data->size);
 +                      data->data = kvmemdup(data->data, data->size, GFP_KERNEL);
                        if (data->size && !data->data) {
                                kfree_sensitive(data->key);
                                kfree_sensitive(data);
                                goto fail;
                        }
  
-                       rhashtable_insert_fast(profile->data, &data->head,
-                                              profile->data->p);
+                       if (rhashtable_insert_fast(profile->data, &data->head,
+                                                  profile->data->p)) {
+                               kfree_sensitive(data->key);
+                               kfree_sensitive(data);
+                               info = "failed to insert data to table";
+                               goto fail;
+                       }
                }
  
                if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL)) {
@@@ -1134,22 -1153,16 +1164,16 @@@ static int verify_header(struct aa_ext 
        return 0;
  }
  
- static bool verify_xindex(int xindex, int table_size)
- {
-       int index, xtype;
-       xtype = xindex & AA_X_TYPE_MASK;
-       index = xindex & AA_X_INDEX_MASK;
-       if (xtype == AA_X_TABLE && index >= table_size)
-               return false;
-       return true;
- }
- /* verify dfa xindexes are in range of transition tables */
- static bool verify_dfa_xindex(struct aa_dfa *dfa, int table_size)
+ /**
+  * verify_dfa_accept_index - verify accept indexes are in range of perms table
+  * @dfa: the dfa to check accept indexes are in range
+  * table_size: the permission table size the indexes should be within
+  */
+ static bool verify_dfa_accept_index(struct aa_dfa *dfa, int table_size)
  {
        int i;
        for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) {
-               if (!verify_xindex(ACCEPT_TABLE(dfa)[i], table_size))
+               if (ACCEPT_TABLE(dfa)[i] >= table_size)
                        return false;
        }
        return true;
@@@ -1186,11 -1199,13 +1210,13 @@@ static bool verify_perms(struct aa_poli
                if (!verify_perm(&pdb->perms[i]))
                        return false;
                /* verify indexes into str table */
-               if (pdb->perms[i].xindex >= pdb->trans.size)
+               if ((pdb->perms[i].xindex & AA_X_TYPE_MASK) == AA_X_TABLE &&
+                   (pdb->perms[i].xindex & AA_X_INDEX_MASK) >= pdb->trans.size)
                        return false;
-               if (pdb->perms[i].tag >= pdb->trans.size)
+               if (pdb->perms[i].tag && pdb->perms[i].tag >= pdb->trans.size)
                        return false;
-               if (pdb->perms[i].label >= pdb->trans.size)
+               if (pdb->perms[i].label &&
+                   pdb->perms[i].label >= pdb->trans.size)
                        return false;
        }
  
@@@ -1212,10 -1227,10 +1238,10 @@@ static int verify_profile(struct aa_pro
        if (!rules)
                return 0;
  
-       if ((rules->file.dfa && !verify_dfa_xindex(rules->file.dfa,
-                                                 rules->file.trans.size)) ||
+       if ((rules->file.dfa && !verify_dfa_accept_index(rules->file.dfa,
+                                                        rules->file.size)) ||
            (rules->policy.dfa &&
-            !verify_dfa_xindex(rules->policy.dfa, rules->policy.trans.size))) {
+            !verify_dfa_accept_index(rules->policy.dfa, rules->policy.size))) {
                audit_iface(profile, NULL, NULL,
                            "Unpack: Invalid named transition", NULL, -EPROTO);
                return -EPROTO;
This page took 0.083658 seconds and 4 git commands to generate.