* [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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.