1 /* Reduced and adapted from Linux: fs/proc/inode.c: proc_reg_open
2    (GPL v2.0).  */
3 
4 /* Types.  */
5 
6 typedef unsigned char u8;
7 typedef _Bool bool;
8 typedef unsigned int gfp_t;
9 
10 struct file;
11 struct kmem_cache;
12 struct proc_dir_entry;
13 
14 struct inode { /* [...snip...] */ };
15 
16 enum {
17  PROC_ENTRY_PERMANENT = 1U << 0,
18 };
19 
20 struct proc_ops {
21  /* [...snip...] */
22  int (*proc_open)(struct inode *, struct file *);
23  /* [...snip...] */
24  int (*proc_release)(struct inode *, struct file *);
25  /* [...snip...] */
26 };
27 
28 struct proc_dir_entry {
29  /* [...snip...] */
30  struct completion *pde_unload_completion;
31  /* [...snip...] */
32  union {
33   const struct proc_ops *proc_ops;
34   const struct file_operations *proc_dir_ops;
35  };
36  /* [...snip...] */
37  u8 flags;
38  /* [...snip...] */
39 };
40 
41 struct pde_opener {
42  /* [...snip...] */
43  struct file *file;
44  /* [...snip...] */
45 };
46 
47 struct proc_inode {
48  /* [...snip...] */
49  struct proc_dir_entry *pde;
50  /* [...snip...] */
51  struct inode vfs_inode;
52 };
53 
54 /* Data.  */
55 
56 static struct kmem_cache *pde_opener_cache __attribute__((__section__(".data..ro_after_init")));
57 
58 /* Functions. */
59 
60 void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags) __attribute__((__malloc__));
61 void kmem_cache_free(struct kmem_cache *, void *);
62 
pde_is_permanent(const struct proc_dir_entry * pde)63 static inline bool pde_is_permanent(const struct proc_dir_entry *pde)
64 {
65  return pde->flags & PROC_ENTRY_PERMANENT;
66 }
67 
PROC_I(const struct inode * inode)68 static inline struct proc_inode *PROC_I(const struct inode *inode)
69 {
70   void *__mptr = (void *)(inode);
71   return ((struct proc_inode *)(__mptr - __builtin_offsetof(struct proc_inode, vfs_inode)));
72 }
73 
PDE(const struct inode * inode)74 static inline struct proc_dir_entry *PDE(const struct inode *inode)
75 {
76  return PROC_I(inode)->pde;
77 }
78 
79 /* We don't want to emit bogus use of uninitialized value 'pdeo'
80    warnings from -Wanalyzer-use-of-uninitialized-value in this function;
81    these would require following infeasible paths in which "release" is
82    first NULL (to avoid the initialization of "pdeo") and then is non-NULL
83    (to access "pdeo").
84 
85    "release" is sufficiently complicated in this function to hit the
86    complexity limit for symbolic values during enode exploration.  */
87 
proc_reg_open(struct inode * inode,struct file * file)88 static int proc_reg_open(struct inode *inode, struct file *file)
89 {
90  struct proc_dir_entry *pde = PDE(inode);
91  int rv = 0;
92  typeof(((struct proc_ops*)0)->proc_open) open;
93  typeof(((struct proc_ops*)0)->proc_release) release;
94  struct pde_opener *pdeo;
95 
96  if (pde_is_permanent(pde)) {
97   open = pde->proc_ops->proc_open;
98   if (open)
99    rv = open(inode, file);
100   return rv;
101  }
102 
103  /* [...snip...] */
104 
105  release = pde->proc_ops->proc_release;
106  if (release) {
107   pdeo = kmem_cache_alloc(pde_opener_cache,
108 			  ((( gfp_t)(0x400u|0x800u))
109 			   | (( gfp_t)0x40u)
110 			   | (( gfp_t)0x80u)));
111   if (!pdeo) {
112    rv = -12;
113    goto out_unuse;
114   }
115  }
116 
117  open = pde->proc_ops->proc_open;
118  if (open)
119   rv = open(inode, file);
120 
121  if (release) {
122   if (rv == 0) {
123 
124    pdeo->file = file; /* { dg-bogus "uninit" } */
125    /* [...snip...] */
126   } else
127    kmem_cache_free(pde_opener_cache, pdeo); /* { dg-bogus "uninit" } */
128  }
129 
130 out_unuse:
131  /* [...snip...] */
132  return rv;
133 }
134