diff options
Diffstat (limited to 'security/integrity/ima/ima_main.c')
-rw-r--r-- | security/integrity/ima/ima_main.c | 57 |
1 files changed, 23 insertions, 34 deletions
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 5a1bf3df11f8..2f9b5d50424e 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -85,42 +85,12 @@ out: | |||
85 | return found; | 85 | return found; |
86 | } | 86 | } |
87 | 87 | ||
88 | /* ima_read_write_check - reflect possible reading/writing errors in the PCR. | ||
89 | * | ||
90 | * When opening a file for read, if the file is already open for write, | ||
91 | * the file could change, resulting in a file measurement error. | ||
92 | * | ||
93 | * Opening a file for write, if the file is already open for read, results | ||
94 | * in a time of measure, time of use (ToMToU) error. | ||
95 | * | ||
96 | * In either case invalidate the PCR. | ||
97 | */ | ||
98 | enum iint_pcr_error { TOMTOU, OPEN_WRITERS }; | ||
99 | static void ima_read_write_check(enum iint_pcr_error error, | ||
100 | struct ima_iint_cache *iint, | ||
101 | struct inode *inode, | ||
102 | const unsigned char *filename) | ||
103 | { | ||
104 | switch (error) { | ||
105 | case TOMTOU: | ||
106 | if (iint->readcount > 0) | ||
107 | ima_add_violation(inode, filename, "invalid_pcr", | ||
108 | "ToMToU"); | ||
109 | break; | ||
110 | case OPEN_WRITERS: | ||
111 | if (iint->writecount > 0) | ||
112 | ima_add_violation(inode, filename, "invalid_pcr", | ||
113 | "open_writers"); | ||
114 | break; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /* | 88 | /* |
119 | * Update the counts given an fmode_t | 89 | * Update the counts given an fmode_t |
120 | */ | 90 | */ |
121 | static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode) | 91 | static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode) |
122 | { | 92 | { |
123 | BUG_ON(!mutex_is_locked(&iint->mutex)); | 93 | assert_spin_locked(&iint->inode->i_lock); |
124 | 94 | ||
125 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | 95 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) |
126 | iint->readcount++; | 96 | iint->readcount++; |
@@ -146,6 +116,7 @@ void ima_counts_get(struct file *file) | |||
146 | fmode_t mode = file->f_mode; | 116 | fmode_t mode = file->f_mode; |
147 | struct ima_iint_cache *iint; | 117 | struct ima_iint_cache *iint; |
148 | int rc; | 118 | int rc; |
119 | bool send_tomtou = false, send_writers = false; | ||
149 | 120 | ||
150 | if (!iint_initialized || !S_ISREG(inode->i_mode)) | 121 | if (!iint_initialized || !S_ISREG(inode->i_mode)) |
151 | return; | 122 | return; |
@@ -153,22 +124,35 @@ void ima_counts_get(struct file *file) | |||
153 | if (!iint) | 124 | if (!iint) |
154 | return; | 125 | return; |
155 | mutex_lock(&iint->mutex); | 126 | mutex_lock(&iint->mutex); |
127 | spin_lock(&inode->i_lock); | ||
128 | |||
156 | if (!ima_initialized) | 129 | if (!ima_initialized) |
157 | goto out; | 130 | goto out; |
131 | |||
158 | rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK); | 132 | rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK); |
159 | if (rc < 0) | 133 | if (rc < 0) |
160 | goto out; | 134 | goto out; |
161 | 135 | ||
162 | if (mode & FMODE_WRITE) { | 136 | if (mode & FMODE_WRITE) { |
163 | ima_read_write_check(TOMTOU, iint, inode, dentry->d_name.name); | 137 | if (iint->readcount) |
138 | send_tomtou = true; | ||
164 | goto out; | 139 | goto out; |
165 | } | 140 | } |
166 | ima_read_write_check(OPEN_WRITERS, iint, inode, dentry->d_name.name); | 141 | |
142 | if (atomic_read(&inode->i_writecount) > 0) | ||
143 | send_writers = true; | ||
167 | out: | 144 | out: |
168 | ima_inc_counts(iint, file->f_mode); | 145 | ima_inc_counts(iint, file->f_mode); |
146 | spin_unlock(&inode->i_lock); | ||
169 | mutex_unlock(&iint->mutex); | 147 | mutex_unlock(&iint->mutex); |
170 | |||
171 | kref_put(&iint->refcount, iint_free); | 148 | kref_put(&iint->refcount, iint_free); |
149 | |||
150 | if (send_tomtou) | ||
151 | ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", | ||
152 | "ToMToU"); | ||
153 | if (send_writers) | ||
154 | ima_add_violation(inode, dentry->d_name.name, "invalid_pcr", | ||
155 | "open_writers"); | ||
172 | } | 156 | } |
173 | 157 | ||
174 | /* | 158 | /* |
@@ -181,6 +165,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | |||
181 | bool dump = false; | 165 | bool dump = false; |
182 | 166 | ||
183 | BUG_ON(!mutex_is_locked(&iint->mutex)); | 167 | BUG_ON(!mutex_is_locked(&iint->mutex)); |
168 | assert_spin_locked(&inode->i_lock); | ||
184 | 169 | ||
185 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { | 170 | if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { |
186 | if (unlikely(iint->readcount == 0)) | 171 | if (unlikely(iint->readcount == 0)) |
@@ -223,7 +208,11 @@ void ima_file_free(struct file *file) | |||
223 | return; | 208 | return; |
224 | 209 | ||
225 | mutex_lock(&iint->mutex); | 210 | mutex_lock(&iint->mutex); |
211 | spin_lock(&inode->i_lock); | ||
212 | |||
226 | ima_dec_counts(iint, inode, file); | 213 | ima_dec_counts(iint, inode, file); |
214 | |||
215 | spin_unlock(&inode->i_lock); | ||
227 | mutex_unlock(&iint->mutex); | 216 | mutex_unlock(&iint->mutex); |
228 | kref_put(&iint->refcount, iint_free); | 217 | kref_put(&iint->refcount, iint_free); |
229 | } | 218 | } |