* [jj-apparmor:apparmor-next 15/32] security/apparmor/policy.c:1381:2: warning: label followed by a declaration is a C23 extension
@ 2026-06-14 18:45 kernel test robot
0 siblings, 0 replies; only message in thread
From: kernel test robot @ 2026-06-14 18:45 UTC (permalink / raw)
To: Maxime Bélair ; +Cc: llvm, oe-kbuild-all, John Johansen, Georgia Garcia
tree: https://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor.git apparmor-next
head: d0691bd5dcaec2350039ecb04fa70faa91ac142d
commit: 7b42f95813dc9ceb6bda35afcf914630909a19f9 [15/32] apparmor: fix potential UAF in aa_replace_profiles
config: riscv-defconfig (https://download.01.org/0day-ci/archive/20260615/202606150256.d5HelD0b-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project 305faf498a4e0b52b40742c927af63ab2082e1a9)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260615/202606150256.d5HelD0b-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202606150256.d5HelD0b-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> security/apparmor/policy.c:1381:2: warning: label followed by a declaration is a C23 extension [-Wc23-extensions]
1381 | ssize_t udata_sz = udata->size;
| ^
1 warning generated.
vim +1381 security/apparmor/policy.c
1154
1155 /**
1156 * aa_replace_profiles - replace profile(s) on the profile list
1157 * @policy_ns: namespace load is occurring on
1158 * @label: label that is attempting to load/replace policy
1159 * @mask: permission mask
1160 * @udata: serialized data stream (NOT NULL)
1161 *
1162 * unpack and replace a profile on the profile list and uses of that profile
1163 * by any task creds via invalidating the old version of the profile, which
1164 * tasks will notice to update their own cred. If the profile does not exist
1165 * on the profile list it is added.
1166 *
1167 * Returns: size of data consumed else error code on failure.
1168 */
1169 ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
1170 u32 mask, struct aa_loaddata *udata)
1171 {
1172 const char *ns_name = NULL, *info = NULL;
1173 struct aa_ns *ns = NULL;
1174 struct aa_load_ent *ent, *tmp;
1175 struct aa_loaddata *rawdata_ent;
1176 const char *op;
1177 ssize_t count, error;
1178 LIST_HEAD(lh);
1179
1180 op = mask & AA_MAY_REPLACE_POLICY ? OP_PROF_REPL : OP_PROF_LOAD;
1181 aa_get_profile_loaddata(udata);
1182 /* released below */
1183 error = aa_unpack(udata, &lh, &ns_name);
1184 if (error)
1185 goto out;
1186
1187 /* ensure that profiles are all for the same ns
1188 * TODO: update locking to remove this constraint. All profiles in
1189 * the load set must succeed as a set or the load will
1190 * fail. Sort ent list and take ns locks in hierarchy order
1191 */
1192 count = 0;
1193 list_for_each_entry(ent, &lh, list) {
1194 if (ns_name) {
1195 if (ent->ns_name &&
1196 strcmp(ent->ns_name, ns_name) != 0) {
1197 info = "policy load has mixed namespaces";
1198 error = -EACCES;
1199 goto fail;
1200 }
1201 } else if (ent->ns_name) {
1202 if (count) {
1203 info = "policy load has mixed namespaces";
1204 error = -EACCES;
1205 goto fail;
1206 }
1207 ns_name = ent->ns_name;
1208 ent->ns_name = NULL;
1209 } else
1210 count++;
1211 }
1212 if (ns_name) {
1213 ns = aa_prepare_ns(policy_ns ? policy_ns : labels_ns(label),
1214 ns_name);
1215 if (IS_ERR(ns)) {
1216 op = OP_PROF_LOAD;
1217 info = "failed to prepare namespace";
1218 error = PTR_ERR(ns);
1219 ns = NULL;
1220 ent = NULL;
1221 goto fail;
1222 }
1223 } else
1224 ns = aa_get_ns(policy_ns ? policy_ns : labels_ns(label));
1225
1226 mutex_lock_nested(&ns->lock, ns->level);
1227 /* check for duplicate rawdata blobs: space and file dedup */
1228 if (!list_empty(&ns->rawdata_list)) {
1229 list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) {
1230 if (aa_rawdata_eq(rawdata_ent, udata)) {
1231 struct aa_loaddata *tmp;
1232
1233 tmp = aa_get_profile_loaddata(rawdata_ent);
1234 /* check we didn't fail the race */
1235 if (tmp) {
1236 aa_put_profile_loaddata(udata);
1237 udata = tmp;
1238 break;
1239 }
1240 }
1241 }
1242 }
1243 /* setup parent and ns info */
1244 list_for_each_entry(ent, &lh, list) {
1245 struct aa_policy *policy;
1246 struct aa_profile *p;
1247
1248 if (aa_g_export_binary)
1249 ent->new->rawdata = aa_get_profile_loaddata(udata);
1250 error = __lookup_replace(ns, ent->new->base.hname,
1251 !(mask & AA_MAY_REPLACE_POLICY),
1252 &ent->old, &info);
1253 if (error)
1254 goto fail_lock;
1255
1256 if (ent->new->rename) {
1257 error = __lookup_replace(ns, ent->new->rename,
1258 !(mask & AA_MAY_REPLACE_POLICY),
1259 &ent->rename, &info);
1260 if (error)
1261 goto fail_lock;
1262 }
1263
1264 /* released when @new is freed */
1265 ent->new->ns = aa_get_ns(ns);
1266
1267 if (ent->old || ent->rename)
1268 continue;
1269
1270 /* no ref on policy only use inside lock */
1271 p = NULL;
1272 policy = __lookup_parent(ns, ent->new->base.hname);
1273 if (!policy) {
1274 /* first check for parent in the load set */
1275 p = __list_lookup_parent(&lh, ent->new);
1276 if (!p) {
1277 /*
1278 * fill in missing parent with null
1279 * profile that doesn't have
1280 * permissions. This allows for
1281 * individual profile loading where
1282 * the child is loaded before the
1283 * parent, and outside of the current
1284 * atomic set. This unfortunately can
1285 * happen with some userspaces. The
1286 * null profile will be replaced once
1287 * the parent is loaded.
1288 */
1289 policy = __create_missing_ancestors(ns,
1290 ent->new->base.hname,
1291 GFP_KERNEL);
1292 if (!policy) {
1293 error = -ENOENT;
1294 info = "parent does not exist";
1295 goto fail_lock;
1296 }
1297 }
1298 }
1299 if (!p && policy != &ns->base)
1300 /* released on profile replacement or free_profile */
1301 p = (struct aa_profile *) policy;
1302 rcu_assign_pointer(ent->new->parent, aa_get_profile(p));
1303 }
1304
1305 /* create new fs entries for introspection if needed */
1306 if (!udata->dents[AAFS_LOADDATA_DIR] && aa_g_export_binary) {
1307 error = __aa_fs_create_rawdata(ns, udata);
1308 if (error) {
1309 info = "failed to create raw_data dir and files";
1310 ent = NULL;
1311 goto fail_lock;
1312 }
1313 }
1314 list_for_each_entry(ent, &lh, list) {
1315 if (!ent->old) {
1316 struct dentry *parent;
1317 if (rcu_access_pointer(ent->new->parent)) {
1318 struct aa_profile *p;
1319 p = aa_deref_parent(ent->new);
1320 parent = prof_child_dir(p);
1321 } else
1322 parent = ns_subprofs_dir(ent->new->ns);
1323 error = __aafs_profile_mkdir(ent->new, parent);
1324 }
1325
1326 if (error) {
1327 info = "failed to create";
1328 goto fail_lock;
1329 }
1330 }
1331
1332 /* Done with checks that may fail - do actual replacement */
1333 __aa_bump_ns_revision(ns);
1334 if (aa_g_export_binary)
1335 __aa_loaddata_update(udata, ns->revision);
1336 list_for_each_entry_safe(ent, tmp, &lh, list) {
1337 list_del_init(&ent->list);
1338 op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL;
1339
1340 if (ent->old && ent->old->rawdata == ent->new->rawdata &&
1341 ent->new->rawdata) {
1342 /* dedup actual profile replacement */
1343 audit_policy(label, op, ns_name, ent->new->base.hname,
1344 "same as current profile, skipping",
1345 error);
1346 /* break refcount cycle with proxy. */
1347 aa_put_proxy(ent->new->label.proxy);
1348 ent->new->label.proxy = NULL;
1349 goto skip;
1350 }
1351
1352 /*
1353 * TODO: finer dedup based on profile range in data. Load set
1354 * can differ but profile may remain unchanged
1355 */
1356 audit_policy(label, op, ns_name, ent->new->base.hname, NULL,
1357 error);
1358
1359 if (ent->old) {
1360 share_name(ent->old, ent->new);
1361 __replace_profile(ent->old, ent->new);
1362 } else {
1363 struct list_head *lh;
1364
1365 if (rcu_access_pointer(ent->new->parent)) {
1366 struct aa_profile *parent;
1367
1368 parent = update_to_newest_parent(ent->new);
1369 lh = &parent->base.profiles;
1370 } else
1371 lh = &ns->base.profiles;
1372 __add_profile(lh, ent->new);
1373 }
1374 skip:
1375 aa_load_ent_free(ent);
1376 }
1377 __aa_labelset_update_subtree(ns);
1378 mutex_unlock(&ns->lock);
1379
1380 out:
> 1381 ssize_t udata_sz = udata->size;
1382
1383 aa_put_ns(ns);
1384 aa_put_profile_loaddata(udata);
1385 kfree(ns_name);
1386
1387 if (error)
1388 return error;
1389 return udata_sz;
1390
1391 fail_lock:
1392 mutex_unlock(&ns->lock);
1393
1394 /* audit cause of failure */
1395 op = (ent && !ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
1396 fail:
1397 audit_policy(label, op, ns_name, ent ? ent->new->base.hname : NULL,
1398 info, error);
1399 /* audit status that rest of profiles in the atomic set failed too */
1400 info = "valid profile in failed atomic policy load";
1401 list_for_each_entry(tmp, &lh, list) {
1402 if (tmp == ent) {
1403 info = "unchecked profile in failed atomic policy load";
1404 /* skip entry that caused failure */
1405 continue;
1406 }
1407 op = (!tmp->old) ? OP_PROF_LOAD : OP_PROF_REPL;
1408 audit_policy(label, op, ns_name, tmp->new->base.hname, info,
1409 error);
1410 }
1411 list_for_each_entry_safe(ent, tmp, &lh, list) {
1412 list_del_init(&ent->list);
1413 aa_load_ent_free(ent);
1414 }
1415
1416 goto out;
1417 }
1418
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-06-14 18:46 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-14 18:45 [jj-apparmor:apparmor-next 15/32] security/apparmor/policy.c:1381:2: warning: label followed by a declaration is a C23 extension kernel test robot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox